From 1b2c3835024915f1dcdc919811140680b7e7c0d9 Mon Sep 17 00:00:00 2001 From: Juan Ferrer Toribio Date: Mon, 28 Oct 2019 17:31:33 +0100 Subject: [PATCH] vnDialog opens in body, nightmare extensions with detailed errors --- e2e/helpers/extensions.js | 268 +++++++----------- e2e/helpers/selectors.js | 148 +++++----- e2e/paths/01-login/01_login.spec.js | 1 + .../02-client-module/05_add_address.spec.js | 2 +- e2e/paths/04-item-module/01_summary.spec.js | 26 +- .../05-ticket-module/13_services.spec.js | 2 +- .../components/array-model/array-model.js | 2 +- front/core/components/autocomplete/index.html | 2 +- front/core/components/autocomplete/index.js | 22 +- front/core/components/autocomplete/style.scss | 2 +- front/core/components/button-menu/index.js | 3 +- front/core/components/button-menu/style.scss | 2 +- front/core/components/button/index.js | 5 +- front/core/components/calendar/index.js | 2 +- front/core/components/calendar/style.scss | 2 +- front/core/components/check/index.js | 11 +- front/core/components/check/style.scss | 15 +- front/core/components/chip/index.js | 2 +- front/core/components/confirm/confirm.js | 9 +- .../core/components/crud-model/crud-model.js | 2 +- front/core/components/date-picker/index.js | 7 +- front/core/components/date-picker/style.scss | 7 - front/core/components/dialog/index.js | 6 +- front/core/components/dialog/index.spec.js | 43 +-- .../core/components/drop-down/drop-down.html | 31 -- front/core/components/drop-down/index.html | 21 ++ .../drop-down/{drop-down.js => index.js} | 138 ++++----- .../{drop-down.spec.js => index.spec.js} | 0 front/core/components/drop-down/style.scss | 2 +- front/core/components/field/index.html | 2 +- front/core/components/field/index.js | 10 +- front/core/components/field/style.scss | 4 +- front/core/components/form-input/index.js | 7 + front/core/components/icon-button/style.scss | 2 +- front/core/components/icon-menu/index.js | 4 +- front/core/components/index.js | 4 +- front/core/components/input-number/index.html | 2 +- front/core/components/menu/menu.js | 19 +- front/core/components/multi-check/style.scss | 2 +- front/core/components/popover/index.html | 8 + front/core/components/popover/index.js | 101 +++++++ .../{popover.spec.js => index.spec.js} | 0 front/core/components/popover/popover.html | 6 - front/core/components/popover/popover.js | 201 ------------- front/core/components/popover/style.scss | 3 +- front/core/components/popup/index.js | 28 +- front/core/components/popup/style.scss | 2 +- front/core/components/radio/style.scss | 5 +- front/core/components/range/style.scss | 2 +- .../core/components/searchbar/search-panel.js | 4 +- front/core/components/searchbar/searchbar.js | 17 +- .../components/searchbar/searchbar.spec.js | 26 +- front/core/components/table/style.scss | 4 +- front/core/components/toggle/index.js | 8 +- front/core/components/toggle/style.scss | 29 +- front/core/components/wday-picker/style.scss | 2 +- front/core/directives/focus.js | 4 +- front/core/directives/popover.js | 8 +- front/core/directives/specs/dialog.spec.js | 6 +- front/core/directives/zoom-image.js | 2 +- front/core/lib/component.js | 45 ++- front/core/lib/event-emitter.js | 8 +- front/core/lib/is-mobile.js | 4 + front/core/locale/es.yml | 5 +- front/salix/components/login/style.scss | 4 +- front/salix/locale/es.yml | 1 + front/salix/styles/misc.scss | 16 +- front/salix/styles/modal-form.scss | 2 +- modules/agency/front/calendar/style.scss | 2 +- modules/agency/front/location/style.scss | 4 +- modules/claim/front/action/style.scss | 2 +- modules/claim/front/detail/style.scss | 2 +- modules/client/front/dms/create/style.scss | 2 +- modules/client/front/dms/edit/style.scss | 2 +- modules/item/back/models/item.json | 48 ++-- modules/item/front/descriptor/style.scss | 2 +- modules/item/front/search-panel/index.html | 101 ++++--- modules/item/front/search-panel/index.js | 75 +++-- modules/item/front/search-panel/locale/es.yml | 2 +- .../order/front/catalog-search-panel/index.js | 5 +- modules/order/front/catalog/index.html | 148 ++++------ modules/order/front/catalog/index.js | 58 ++-- modules/order/front/catalog/index.spec.js | 16 +- modules/order/front/descriptor/index.js | 1 - modules/order/front/descriptor/style.scss | 5 - modules/order/front/filter/index.html | 80 ++++-- modules/order/front/filter/index.js | 25 +- modules/order/front/filter/index.spec.js | 3 - modules/order/front/line/index.html | 146 +++++----- modules/order/front/line/style.scss | 15 +- modules/order/front/prices-popover/index.html | 144 +++++----- modules/order/front/prices-popover/index.js | 32 ++- modules/order/front/prices-popover/style.scss | 91 ++---- modules/order/front/volume/index.html | 99 +++---- modules/order/front/volume/style.scss | 12 +- modules/ticket/front/descriptor/style.scss | 2 +- modules/ticket/front/dms/create/index.js | 1 - modules/ticket/front/dms/create/style.scss | 7 - modules/ticket/front/dms/edit/index.js | 1 - modules/ticket/front/dms/edit/style.scss | 7 - .../ticket/front/request/create/style.scss | 2 +- modules/ticket/front/sale/style.scss | 4 +- modules/ticket/front/services/index.html | 3 +- modules/ticket/front/services/index.js | 2 - 104 files changed, 1133 insertions(+), 1408 deletions(-) delete mode 100644 front/core/components/date-picker/style.scss delete mode 100755 front/core/components/drop-down/drop-down.html create mode 100755 front/core/components/drop-down/index.html rename front/core/components/drop-down/{drop-down.js => index.js} (85%) rename front/core/components/drop-down/{drop-down.spec.js => index.spec.js} (100%) create mode 100644 front/core/components/popover/index.html create mode 100644 front/core/components/popover/index.js rename front/core/components/popover/{popover.spec.js => index.spec.js} (100%) delete mode 100644 front/core/components/popover/popover.html delete mode 100644 front/core/components/popover/popover.js create mode 100644 front/core/lib/is-mobile.js delete mode 100644 modules/order/front/descriptor/style.scss delete mode 100644 modules/ticket/front/dms/create/style.scss delete mode 100644 modules/ticket/front/dms/edit/style.scss diff --git a/e2e/helpers/extensions.js b/e2e/helpers/extensions.js index 4148a4a05..11fb86416 100644 --- a/e2e/helpers/extensions.js +++ b/e2e/helpers/extensions.js @@ -6,7 +6,7 @@ import config from './config.js'; let currentUser; -let asyncActions = { +let actions = { // Generic extensions clickIfExists: async function(selector) { @@ -15,16 +15,16 @@ let asyncActions = { return exists; }, - hasClass: async function(selector, className) { - return await this.evaluate((selector, className) => { - document.querySelector(selector).classList.contains(className); - }, selector, className); - }, - parsedUrl: async function() { return new URL(await this.url()); }, + waitUntilNotPresent: async function(selector) { + await this.wait(selector => { + return document.querySelector(selector) == null; + }, selector); + }, + // Salix specific extensions changeLanguageToEnglish: async function() { @@ -116,31 +116,21 @@ let asyncActions = { }, selector, time); }, - isDisabled: async function(selector) { - return await this.hasClass(selector, 'disabled'); - } -}; - -let actions = { - clearTextarea: function(selector, done) { - this.wait(selector) + clearTextarea: function(selector) { + return this.wait(selector) .evaluate(inputSelector => { return document.querySelector(inputSelector).value = ''; - }, selector) - .then(done) - .catch(done); + }, selector); }, - clearInput: function(selector, done) { - this.wait(selector) + clearInput: function(selector) { + return this.wait(selector) .evaluate(selector => { let $ctrl = document.querySelector(selector).closest('.vn-field').$ctrl; $ctrl.field = null; $ctrl.$.$apply(); $ctrl.input.dispatchEvent(new Event('change')); - }, selector) - .then(done) - .catch(done); + }, selector); }, getProperty: function(selector, property, done) { @@ -149,47 +139,39 @@ let actions = { }, done, selector, property); }, - waitPropertyLength: function(selector, property, minLength, done) { - this.wait((selector, property, minLength) => { + waitPropertyLength: function(selector, property, minLength) { + return this.wait((selector, property, minLength) => { const element = document.querySelector(selector); return element && element[property] != null && element[property] !== '' && element[property].length >= minLength; }, selector, property, minLength) - .getProperty(selector, property) - .then(result => done(null, result), done); + .getProperty(selector, property); }, - waitPropertyValue: function(selector, property, status, done) { - this.wait(selector) + waitPropertyValue: function(selector, property, status) { + return this.wait(selector) .wait((selector, property, status) => { const element = document.querySelector(selector); return element[property] === status; - }, selector, property, status) - .then(done) - .catch(done); + }, selector, property, status); }, - waitToGetProperty: function(selector, property, done) { - this.wait((selector, property) => { + waitToGetProperty: function(selector, property) { + return this.wait((selector, property) => { const element = document.querySelector(selector); return element && element[property] != null && element[property] !== ''; }, selector, property) - .getProperty(selector, property) - .then(result => done(null, result), done); + .getProperty(selector, property); }, - write: function(selector, text, done) { - this.wait(selector) - .type(selector, text) - .then(done) - .catch(done); + write: function(selector, text) { + return this.wait(selector) + .type(selector, text); }, - waitToClick: function(selector, done) { - this.wait(selector) - .click(selector) - .then(done) - .catch(done); + waitToClick: function(selector) { + return this.wait(selector) + .click(selector); }, focusElement: function(selector, done) { @@ -197,9 +179,7 @@ let actions = { .evaluate_now(selector => { let element = document.querySelector(selector); element.focus(); - }, done, selector) - .then(done) - .catch(done); + }, done, selector); }, isVisible: function(selector, done) { @@ -245,29 +225,23 @@ let actions = { }, done, selector); }, - waitImgLoad: function(selector, done) { - this.wait(selector) + waitImgLoad: function(selector) { + return this.wait(selector) .wait(selector => { const imageReady = document.querySelector(selector).complete; return imageReady; - }, selector) - .then(done) - .catch(() => { - done(new Error(`image ${selector}, load timed out`)); - }); + }, selector); }, - clickIfVisible: function(selector, done) { - this.wait(selector) + clickIfVisible: function(selector) { + return this.wait(selector) .isVisible(selector) .then(visible => { if (visible) return this.click(selector); throw new Error(`invisible selector: ${selector}`); - }) - .then(done) - .catch(done); + }); }, countElement: function(selector, done) { @@ -276,56 +250,40 @@ let actions = { }, done, selector); }, - waitForNumberOfElements: function(selector, count, done) { - this.wait((selector, count) => { + waitForNumberOfElements: function(selector, count) { + return this.wait((selector, count) => { return document.querySelectorAll(selector).length === count; - }, selector, count) - .then(done) - .catch(() => { - done(new Error(`.waitForNumberOfElements() for ${selector}, count ${count} timed out`)); - }); + }, selector, count); }, - waitForClassNotPresent: function(selector, className, done) { - this.wait(selector) + waitForClassNotPresent: function(selector, className) { + return this.wait(selector) .wait((selector, className) => { if (!document.querySelector(selector).classList.contains(className)) return true; - }, selector, className) - .then(done) - .catch(() => { - done(new Error(`.waitForClassNotPresent() for ${selector}, class ${className} timed out`)); - }); + }, selector, className); }, - waitForClassPresent: function(selector, className, done) { - this.wait(selector) + waitForClassPresent: function(selector, className) { + return this.wait(selector) .wait((elementSelector, targetClass) => { if (document.querySelector(elementSelector).classList.contains(targetClass)) return true; - }, selector, className) - .then(done) - .catch(() => { - done(new Error(`.waitForClassPresent() for ${selector}, class ${className} timed out`)); - }); + }, selector, className); }, - waitForTextInElement: function(selector, text, done) { - this.wait(selector) + waitForTextInElement: function(selector, text) { + return this.wait(selector) .wait((selector, text) => { return document.querySelector(selector).innerText.toLowerCase().includes(text.toLowerCase()); - }, selector, text) - .then(done) - .catch(done); + }, selector, text); }, - waitForTextInInput: function(selector, text, done) { - this.wait(selector) + waitForTextInInput: function(selector, text) { + return this.wait(selector) .wait((selector, text) => { return document.querySelector(selector).value.toLowerCase().includes(text.toLowerCase()); - }, selector, text) - .then(done) - .catch(done); + }, selector, text); }, waitForInnerText: function(selector, done) { @@ -339,20 +297,16 @@ let actions = { }, done, selector); }, - waitForEmptyInnerText: function(selector, done) { - this.wait(selector => { + waitForEmptyInnerText: function(selector) { + return this.wait(selector => { return document.querySelector(selector).innerText == ''; - }, selector) - .then(done) - .catch(done); + }, selector); }, - waitForURL: function(hashURL, done) { - this.wait(hash => { + waitForURL: function(hashURL) { + return this.wait(hash => { return document.location.hash.includes(hash); - }, hashURL) - .then(done) - .catch(done); + }, hashURL); }, waitForShapes: function(selector, done) { @@ -368,11 +322,9 @@ let actions = { return shapesList; }, done, selector); }, - waitForSnackbar: function(done) { - this.wait(500).waitForShapes('vn-snackbar .shape .text') - .then(shapes => { - done(null, shapes); - }).catch(done); + waitForSnackbar: function() { + return this.wait(500) + .waitForShapes('vn-snackbar .shape .text'); }, waitForLastShape: function(selector, done) { @@ -384,15 +336,13 @@ let actions = { }, done, selector); }, - waitForLastSnackbar: function(done) { - this.wait(500).waitForLastShape('vn-snackbar .shape .text') - .then(shapes => { - done(null, shapes); - }).catch(done); + waitForLastSnackbar: function() { + return this.wait(500) + .waitForLastShape('vn-snackbar .shape .text'); }, - accessToSearchResult: function(searchValue, done) { - this.clearInput('vn-searchbar input') + accessToSearchResult: function(searchValue) { + return this.clearInput('vn-searchbar input') .write('vn-searchbar input', searchValue) .click('vn-searchbar vn-icon[icon="search"]') .wait(100) @@ -405,13 +355,11 @@ let actions = { return this.waitToClick('ui-view vn-card vn-td'); return this.waitToClick('ui-view vn-card a'); - }) - .then(done) - .catch(done); + }); }, - accessToSection: function(sectionRoute, done) { - this.wait(`vn-left-menu`) + accessToSection: function(sectionRoute) { + return this.wait(`vn-left-menu`) .evaluate(sectionRoute => { return document.querySelector(`vn-left-menu ul li ul li > a[ui-sref="${sectionRoute}"]`) != null; }, sectionRoute) @@ -422,45 +370,35 @@ let actions = { return this.waitToClick('vn-left-menu .collapsed') .wait('vn-left-menu .expanded') .waitToClick(`vn-left-menu li > a[ui-sref="${sectionRoute}"]`); - }) - .then(done) - .catch(done); + }); }, - autocompleteSearch: function(autocompleteSelector, searchValue, done) { - this.waitToClick(`${autocompleteSelector} input`) - .write(`.vn-popover.shown .vn-drop-down input`, searchValue) - .waitToClick(`.vn-popover.shown .vn-drop-down li.active`) + autocompleteSearch: function(autocompleteSelector, searchValue) { + return this.waitToClick(`${autocompleteSelector} input`) + .write(`.vn-drop-down.shown input`, searchValue) + .waitToClick(`.vn-drop-down.shown li.active`) .wait((autocompleteSelector, searchValue) => { return document.querySelector(`${autocompleteSelector} input`).value .toLowerCase() .includes(searchValue.toLowerCase()); - }, autocompleteSelector, searchValue) - .then(done) - .catch(() => { - done(new Error(`.autocompleteSearch() for value ${searchValue} in ${autocompleteSelector} timed out`)); - }); + }, autocompleteSelector, searchValue); }, - reloadSection: function(sectionRoute, done) { - this.waitToClick('vn-icon[icon="desktop_windows"]') + reloadSection: function(sectionRoute) { + return this.waitToClick('vn-icon[icon="desktop_windows"]') .wait('vn-card.summary') - .waitToClick(`vn-left-menu li > a[ui-sref="${sectionRoute}"]`) - .then(done) - .catch(done); + .waitToClick(`vn-left-menu li > a[ui-sref="${sectionRoute}"]`); }, - forceReloadSection: function(sectionRoute, done) { - this.waitToClick('vn-icon[icon="desktop_windows"]') + forceReloadSection: function(sectionRoute) { + return this.waitToClick('vn-icon[icon="desktop_windows"]') .waitToClick('button[response="ACCEPT"]') .wait('vn-card.summary') - .waitToClick(`vn-left-menu li > a[ui-sref="${sectionRoute}"]`) - .then(done) - .catch(done); + .waitToClick(`vn-left-menu li > a[ui-sref="${sectionRoute}"]`); }, - checkboxState: function(selector, done) { - this.wait(selector) + checkboxState: function(selector) { + return this.wait(selector) .evaluate(selector => { let checkbox = document.querySelector(selector); switch (checkbox.$ctrl.field) { @@ -471,40 +409,38 @@ let actions = { default: return 'unchecked'; } - }, selector) - .then(res => done(null, res)) - .catch(done); + }, selector); }, - isDisabled: function(selector, done) { - this.wait(selector) + isDisabled: function(selector) { + return this.wait(selector) .evaluate(selector => { let element = document.querySelector(selector); return element.$ctrl.disabled; - }, selector) - .then(res => done(null, res)) - .catch(done); + }, selector); }, - waitForSpinnerLoad: function(done) { - let spinnerSelector = 'vn-spinner > div'; - this.waitForClassNotPresent(spinnerSelector, 'is-active') - .then(done) - .catch(done); + waitForSpinnerLoad: function() { + return this.waitForClassNotPresent('vn-spinner > div', 'is-active'); }, }; -for (let name in asyncActions) { - let fn = asyncActions[name]; - +for (let name in actions) { Nightmare.action(name, function(...args) { let done = args[args.length - 1]; - fn.apply(this, args) - .then(res => done(null, res), done); + let promise = actions[name].apply(this, args); + + if (promise) { + promise + .then(res => done(null, res)) + .catch(err => { + let errArgs = args.slice(0, args.length - 1); + errArgs = errArgs + .map(i => JSON.stringify(i)) + .join(', '); + + done(new Error(`.${name}(${errArgs}) failed: ${err.message}`)); + }); + } }); } - -Object.keys(actions).forEach(function(name) { - let fn = actions[name]; - Nightmare.action(name, fn); -}); diff --git a/e2e/helpers/selectors.js b/e2e/helpers/selectors.js index 2b9caacd5..13b87f349 100644 --- a/e2e/helpers/selectors.js +++ b/e2e/helpers/selectors.js @@ -18,7 +18,7 @@ export default { userConfigFirstAutocompleteClear: '#localWarehouse .icons > vn-icon[icon=clear]', userConfigSecondAutocompleteClear: '#localBank .icons > vn-icon[icon=clear]', userConfigThirdAutocompleteClear: '#localCompany .icons > vn-icon[icon=clear]', - acceptButton: 'vn-confirm button[response=ACCEPT]' + acceptButton: '.vn-confirm.shown button[response=ACCEPT]' }, clientsIndex: { searchClientInput: `vn-textfield input`, @@ -44,7 +44,7 @@ export default { }, clientDescriptor: { moreMenu: 'vn-client-descriptor vn-icon-menu[icon=more_vert]', - simpleTicketButton: '.vn-popover.shown .vn-drop-down li' + simpleTicketButton: '.vn-drop-down.shown li' }, clientBasicData: { basicDataButton: 'vn-left-menu a[ui-sref="client.card.basicData"]', @@ -62,7 +62,7 @@ export default { socialNameInput: `vn-textfield input[name="socialName"]`, fiscalIdInput: `vn-textfield input[name="fi"]`, equalizationTaxCheckbox: 'vn-check[ng-model="$ctrl.client.isEqualizated"]', - acceptPropagationButton: 'vn-client-fiscal-data > vn-confirm button[response=ACCEPT]', + acceptPropagationButton: '.vn-confirm.shown button[response=ACCEPT]', addressInput: `vn-textfield input[name="street"]`, postcodeInput: `vn-textfield input[name="postcode"]`, cityInput: `vn-textfield input[name="city"]`, @@ -87,10 +87,10 @@ export default { swiftBicAutocomplete: 'vn-client-billing-data vn-autocomplete[ng-model="$ctrl.client.bankEntityFk"]', clearswiftBicButton: 'vn-client-billing-data vn-autocomplete[ng-model="$ctrl.client.bankEntityFk"] .icons > vn-icon[icon=clear]', newBankEntityButton: 'vn-client-billing-data vn-icon-button[vn-tooltip="New bank entity"] > button', - newBankEntityName: 'vn-client-billing-data > vn-dialog vn-textfield[label="Name"] input', - newBankEntityBIC: 'vn-client-billing-data > vn-dialog vn-textfield[label="Swift / BIC"] input', - newBankEntityCode: 'vn-client-billing-data > vn-dialog vn-textfield[label="Entity Code"] input', - acceptBankEntityButton: 'vn-client-billing-data > vn-dialog button[response="ACCEPT"]', + newBankEntityName: '.vn-dialog.shown vn-textfield[label="Name"] input', + newBankEntityBIC: '.vn-dialog.shown vn-textfield[label="Swift / BIC"] input', + newBankEntityCode: '.vn-dialog.shown vn-textfield[label="Entity Code"] input', + acceptBankEntityButton: '.vn-dialog.shown button[response="ACCEPT"]', saveButton: `button[type=submit]` }, clientAddresses: { @@ -163,9 +163,9 @@ export default { balanceButton: 'vn-left-menu a[ui-sref="client.card.balance.index"]', companyAutocomplete: 'vn-client-balance-index vn-autocomplete[ng-model="$ctrl.companyFk"]', newPaymentButton: `vn-float-button`, - newPaymentBank: 'vn-client-balance-create vn-autocomplete[ng-model="$ctrl.receipt.bankFk"]', - newPaymentAmountInput: 'vn-client-balance-create vn-input-number[ng-model="$ctrl.receipt.amountPaid"] input', - saveButton: 'vn-client-balance-create vn-button[label="Save"]', + newPaymentBank: '.vn-dialog.shown vn-autocomplete[ng-model="$ctrl.receipt.bankFk"]', + newPaymentAmountInput: '.vn-dialog.shown vn-input-number[ng-model="$ctrl.receipt.amountPaid"] input', + saveButton: '.vn-dialog.shown vn-button[label="Save"]', firstBalanceLine: 'vn-client-balance-index vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(8)' }, @@ -177,7 +177,7 @@ export default { deleteFileButton: 'vn-client-dms-index vn-tr:nth-child(1) vn-icon-button[icon="delete"]', firstDocWorker: 'vn-client-dms-index vn-td:nth-child(8) > span', firstDocWorkerDescriptor: '.vn-popover.shown vn-worker-descriptor', - acceptDeleteButton: 'vn-client-dms-index > vn-confirm button[response="ACCEPT"]' + acceptDeleteButton: '.vn-confirm.shown button[response="ACCEPT"]' }, itemsIndex: { searchIcon: 'vn-item-index vn-searchbar vn-icon[icon="search"]', @@ -185,26 +185,26 @@ export default { searchResult: 'vn-item-index a.vn-tr', searchResultPreviewButton: 'vn-item-index .buttons > [icon="desktop_windows"]', searchResultCloneButton: 'vn-item-index .buttons > [icon="icon-clone"]', - acceptClonationAlertButton: 'vn-item-index [vn-id="clone"] [response="ACCEPT"]', + acceptClonationAlertButton: '.vn-confirm.shown [response="ACCEPT"]', searchItemInput: 'vn-searchbar vn-textfield input', searchButton: 'vn-searchbar vn-icon[icon="search"]', - closeItemSummaryPreview: 'vn-item-index [vn-id="preview"] button.close', + closeItemSummaryPreview: '.vn-popup.shown', fieldsToShowButton: 'vn-item-index vn-table > div > div > vn-icon-button[icon="menu"]', - fieldsToShowForm: 'vn-item-index vn-table > div > div > vn-dialog > div > form', + fieldsToShowForm: '.vn-dialog.shown form', firstItemImage: 'vn-item-index vn-tbody > a:nth-child(1) > vn-td:nth-child(1)', firstItemId: 'vn-item-index vn-tbody > a:nth-child(1) > vn-td:nth-child(2)', - idCheckbox: 'vn-item-index vn-dialog form vn-horizontal:nth-child(2) > vn-check', - stemsCheckbox: 'vn-item-index vn-dialog form vn-horizontal:nth-child(3) > vn-check', - sizeCheckbox: 'vn-item-index vn-dialog form vn-horizontal:nth-child(4) > vn-check', - nicheCheckbox: 'vn-item-index vn-dialog form vn-horizontal:nth-child(5) > vn-check', - typeCheckbox: 'vn-item-index vn-dialog form vn-horizontal:nth-child(6) > vn-check', - categoryCheckbox: 'vn-item-index vn-dialog form vn-horizontal:nth-child(7) > vn-check', - intrastadCheckbox: 'vn-item-index vn-dialog form vn-horizontal:nth-child(8) > vn-check', - originCheckbox: 'vn-item-index vn-dialog form vn-horizontal:nth-child(9) > vn-check', - buyerCheckbox: 'vn-item-index vn-dialog form vn-horizontal:nth-child(10) > vn-check', - destinyCheckbox: 'vn-item-index vn-dialog form vn-horizontal:nth-child(11) > vn-check', - taxClassCheckbox: 'vn-item-index vn-dialog form vn-horizontal:nth-child(12) > vn-check', - saveFieldsButton: 'vn-item-index vn-dialog vn-horizontal:nth-child(16) > vn-button > button' + idCheckbox: '.vn-dialog.shown form vn-horizontal:nth-child(2) > vn-check', + stemsCheckbox: '.vn-dialog.shown form vn-horizontal:nth-child(3) > vn-check', + sizeCheckbox: '.vn-dialog.shown form vn-horizontal:nth-child(4) > vn-check', + nicheCheckbox: '.vn-dialog.shown form vn-horizontal:nth-child(5) > vn-check', + typeCheckbox: '.vn-dialog.shown form vn-horizontal:nth-child(6) > vn-check', + categoryCheckbox: '.vn-dialog.shown form vn-horizontal:nth-child(7) > vn-check', + intrastadCheckbox: '.vn-dialog.shown form vn-horizontal:nth-child(8) > vn-check', + originCheckbox: '.vn-dialog.shown form vn-horizontal:nth-child(9) > vn-check', + buyerCheckbox: '.vn-dialog.shown form vn-horizontal:nth-child(10) > vn-check', + destinyCheckbox: '.vn-dialog.shown form vn-horizontal:nth-child(11) > vn-check', + taxClassCheckbox: '.vn-dialog.shown form vn-horizontal:nth-child(12) > vn-check', + saveFieldsButton: '.vn-dialog.shown vn-horizontal:nth-child(16) > vn-button > button' }, itemCreateView: { temporalName: `vn-textfield input[name="provisionalName"]`, @@ -217,11 +217,11 @@ export default { itemDescriptor: { goBackToModuleIndexButton: 'vn-item-descriptor a[href="#!/item/index"]', moreMenu: 'vn-item-descriptor vn-icon-menu[icon=more_vert]', - moreMenuRegularizeButton: '.vn-popover.shown .vn-drop-down li[name="Regularize stock"]', - regularizeQuantityInput: 'vn-item-descriptor vn-dialog tpl-body > div > vn-textfield input', - regularizeWarehouseAutocomplete: 'vn-item-descriptor vn-dialog vn-autocomplete[ng-model="$ctrl.warehouseFk"]', + moreMenuRegularizeButton: '.vn-drop-down.shown li[name="Regularize stock"]', + regularizeQuantityInput: '.vn-dialog.shown tpl-body > div > vn-textfield input', + regularizeWarehouseAutocomplete: '.vn-dialog.shown vn-autocomplete[ng-model="$ctrl.warehouseFk"]', editButton: 'vn-item-card vn-item-descriptor vn-float-button[icon="edit"]', - regularizeSaveButton: 'vn-item-descriptor > vn-dialog > div > form > div.buttons > tpl-buttons > button', + regularizeSaveButton: '.vn-dialog.shown tpl-buttons > button', inactiveIcon: 'vn-item-descriptor vn-icon[icon="icon-unavailable"]', navigateBackToIndex: 'vn-item-descriptor vn-icon[icon="chevron_left"]' }, @@ -336,11 +336,11 @@ export default { searchButton: 'vn-ticket-index vn-searchbar vn-icon[icon="search"]', searchWeeklyButton: 'vn-ticket-weekly-index vn-searchbar vn-icon[icon="search"]', moreMenu: 'vn-ticket-index vn-icon-menu[icon=more_vert]', - moreMenuWeeklyTickets: '.vn-popover.shown .vn-drop-down li:nth-child(2)', + moreMenuWeeklyTickets: '.vn-drop-down.shown li:nth-child(2)', sixthWeeklyTicket: 'vn-ticket-weekly-index vn-table vn-tr:nth-child(6) vn-autocomplete[ng-model="weekly.weekDay"] input', weeklyTicket: 'vn-ticket-weekly-index vn-table > div > vn-tbody > vn-tr', firstWeeklyTicketDeleteIcon: 'vn-ticket-weekly-index vn-tr:nth-child(1) vn-icon-button[icon="delete"]', - acceptDeleteTurn: 'vn-ticket-weekly-index > vn-confirm[vn-id="deleteWeekly"] button[response="ACCEPT"]' + acceptDeleteTurn: '.vn-confirm.shown button[response="ACCEPT"]' }, createTicketView: { clientAutocomplete: 'vn-ticket-create vn-autocomplete[ng-model="$ctrl.clientFk"]', @@ -355,24 +355,24 @@ export default { stateLabelValue: 'vn-ticket-descriptor vn-label-value[label="State"]', goBackToModuleIndexButton: 'vn-ticket-descriptor a[ui-sref="ticket.index"]', moreMenu: 'vn-ticket-descriptor vn-icon-menu[icon=more_vert]', - moreMenuAddStowaway: '.vn-popover.shown .vn-drop-down li[name="Add stowaway"]', - moreMenuDeleteStowawayButton: '.vn-popover.shown .vn-drop-down li[name="Remove stowaway"]', - moreMenuAddToTurn: '.vn-popover.shown .vn-drop-down li[name="Add turn"]', - moreMenuDeleteTicket: '.vn-popover.shown .vn-drop-down li[name="Delete ticket"]', - moreMenuMakeInvoice: '.vn-popover.shown .vn-drop-down li[name="Make invoice"]', - moreMenuChangeShippedHour: '.vn-popover.shown .vn-drop-down li[name="Change shipped hour"]', - changeShippedHourDialog: 'vn-ticket-descriptor vn-dialog[vn-id="changeShippedDialog"]', - changeShippedHourInput: 'vn-dialog[vn-id="changeShippedDialog"] [ng-model="$ctrl.newShipped"]', - addStowawayDialogFirstTicket: 'vn-ticket-descriptor > vn-add-stowaway > vn-dialog vn-table vn-tbody vn-tr', + moreMenuAddStowaway: '.vn-drop-down.shown li[name="Add stowaway"]', + moreMenuDeleteStowawayButton: '.vn-drop-down.shown li[name="Remove stowaway"]', + moreMenuAddToTurn: '.vn-drop-down.shown li[name="Add turn"]', + moreMenuDeleteTicket: '.vn-drop-down.shown li[name="Delete ticket"]', + moreMenuMakeInvoice: '.vn-drop-down.shown li[name="Make invoice"]', + moreMenuChangeShippedHour: '.vn-drop-down.shown li[name="Change shipped hour"]', + changeShippedHourDialog: '.vn-dialog.shown', + changeShippedHourInput: '.vn-dialog.shown [ng-model="$ctrl.newShipped"]', + addStowawayDialogFirstTicket: '.vn-dialog.shown vn-table vn-tbody vn-tr', shipButton: 'vn-ticket-descriptor vn-icon[icon="icon-stowaway"]', - thursdayButton: 'vn-ticket-descriptor > vn-dialog > div > form > div.body > tpl-body > div > vn-tool-bar > vn-button:nth-child(4)', - saturdayButton: 'vn-ticket-descriptor > vn-dialog > div > form > div.body > tpl-body > div > vn-tool-bar > vn-button:nth-child(6)', - closeStowawayDialog: 'vn-ticket-descriptor > vn-add-stowaway > vn-dialog > div > button[class="close"]', - acceptDeleteButton: 'vn-ticket-descriptor button[response="ACCEPT"]', - acceptChangeHourButton: 'vn-ticket-descriptor vn-dialog[vn-id="changeShippedDialog"] button[response="ACCEPT"]', + thursdayButton: '.vn-popup.shown vn-tool-bar > vn-button:nth-child(4)', + saturdayButton: '.vn-popup.shown vn-tool-bar > vn-button:nth-child(6)', + closeStowawayDialog: '.vn-dialog.shown button[class="close"]', + acceptDeleteButton: '.vn-dialog.shown button[response="ACCEPT"]', + acceptChangeHourButton: '.vn-dialog.shown button[response="ACCEPT"]', descriptorDeliveryDate: 'vn-ticket-descriptor > div > div.body > div.attributes > vn-label-value:nth-child(6) > section > span', - acceptInvoiceOutButton: 'vn-ticket-descriptor vn-confirm[vn-id="makeInvoiceConfirmation"] button[response="ACCEPT"]', - acceptDeleteStowawayButton: 'vn-ticket-descriptor > vn-remove-stowaway button[response="ACCEPT"]' + acceptInvoiceOutButton: '.vn-confirm.shown button[response="ACCEPT"]', + acceptDeleteStowawayButton: '.vn-dialog.shown button[response="ACCEPT"]' }, ticketNotes: { firstNoteRemoveButton: 'vn-icon[icon="delete"]', @@ -384,7 +384,7 @@ export default { ticketExpedition: { expeditionButton: 'vn-left-menu a[ui-sref="ticket.card.expedition"]', secondExpeditionRemoveButton: 'vn-ticket-expedition vn-table div > vn-tbody > vn-tr:nth-child(2) > vn-td:nth-child(1) > vn-icon-button[icon="delete"]', - acceptDeleteRowButton: 'vn-ticket-expedition > vn-confirm[vn-id="delete-expedition"] button[response=ACCEPT]', + acceptDeleteRowButton: '.vn-confirm.shown button[response=ACCEPT]', expeditionRow: 'vn-ticket-expedition vn-table vn-tbody > vn-tr' }, ticketPackages: { @@ -405,11 +405,11 @@ export default { newItemFromCatalogButton: 'vn-ticket-sale vn-float-button[icon="add"]', newItemButton: 'vn-ticket-sale > vn-vertical > vn-card > vn-vertical > vn-one > vn-icon-button > button > vn-icon > i', moreMenu: 'vn-ticket-sale vn-tool-bar > vn-button-menu[vn-id="more-button"] > div > button', - moreMenuCreateClaim: '.vn-popover.shown .vn-drop-down li[name="Add claim"]', - moreMenuReserve: '.vn-popover.shown .vn-drop-down li[name="Mark as reserved"]', - moreMenuUnmarkReseved: '.vn-popover.shown .vn-drop-down li[name="Unmark as reserved"]', - moreMenuUpdateDiscount: '.vn-popover.shown .vn-drop-down li[name="Update discount"]', - moreMenuUpdateDiscountInput: 'vn-ticket-sale vn-dialog form vn-ticket-sale-edit-discount vn-input-number[ng-model="$ctrl.newDiscount"] input', + moreMenuCreateClaim: '.vn-drop-down.shown li[name="Add claim"]', + moreMenuReserve: '.vn-drop-down.shown li[name="Mark as reserved"]', + moreMenuUnmarkReseved: '.vn-drop-down.shown li[name="Unmark as reserved"]', + moreMenuUpdateDiscount: '.vn-drop-down.shown li[name="Update discount"]', + moreMenuUpdateDiscountInput: '.vn-dialog.shown form vn-ticket-sale-edit-discount vn-input-number[ng-model="$ctrl.newDiscount"] input', transferQuantityInput: '.vn-popover.shown vn-table > div > vn-tbody > vn-tr > vn-td-editable > span > text', transferQuantityCell: '.vn-popover.shown vn-table > div > vn-tbody > vn-tr > vn-td-editable', firstSaleClaimIcon: 'vn-ticket-sale vn-table vn-tbody > vn-tr:nth-child(1) vn-icon[icon="icon-claims"]', @@ -421,7 +421,7 @@ export default { firstSaleQuantityCell: 'vn-ticket-sale vn-tr:nth-child(1) > vn-td-editable:nth-child(5)', firstSaleQuantityClearInput: 'vn-textfield[ng-model="sale.quantity"] div.suffix > i', firstSaleIdAutocomplete: 'vn-ticket-sale vn-table vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(4) > vn-autocomplete', - idAutocompleteFirstResult: '.vn-popover.shown .vn-drop-down li', + idAutocompleteFirstResult: '.vn-drop-down.shown li', firstSalePrice: 'vn-ticket-sale vn-table vn-tr:nth-child(1) > vn-td:nth-child(7) > span', firstSalePriceInput: '.vn-popover.shown vn-input-number input', firstSaleDiscount: 'vn-ticket-sale vn-table vn-tr:nth-child(1) > vn-td:nth-child(8) > span', @@ -453,8 +453,8 @@ export default { moveToTicketInputClearButton: '.vn-popover.shown i[title="Clear"]', moveToTicketButton: '.vn-popover.shown vn-icon[icon="arrow_forward_ios"]', moveToNewTicketButton: '.vn-popover.shown vn-button[label="New ticket"]', - acceptDeleteLineButton: 'vn-ticket-sale > vn-confirm[vn-id="delete-lines"] button[response=ACCEPT]', - acceptDeleteTicketButton: 'vn-ticket-sale > vn-confirm[vn-id="delete-ticket"] button[response=ACCEPT]', + acceptDeleteLineButton: '.vn-confirm.shown button[response=ACCEPT]', + acceptDeleteTicketButton: '.vn-confirm.shown button[response=ACCEPT]', stateMenuButton: 'vn-ticket-sale vn-tool-bar > vn-button-menu[label="State"]' }, ticketTracking: { @@ -504,10 +504,10 @@ export default { firstPriceInput: 'vn-ticket-service vn-input-number[label="Price"] input', firstVatTypeAutocomplete: 'vn-ticket-service vn-autocomplete[label="Tax class"]', fistDeleteServiceButton: 'vn-ticket-service form vn-horizontal:nth-child(1) vn-icon-button[icon="delete"]', - newDescriptionInput: 'vn-ticket-service > vn-dialog vn-textfield[ng-model="$ctrl.newServiceType.name"] input', + newDescriptionInput: '.vn-dialog.shown vn-textfield[ng-model="$ctrl.newServiceType.name"] input', serviceLine: 'vn-ticket-service > form > vn-card > vn-one:nth-child(2) > vn-horizontal', saveServiceButton: `button[type=submit]`, - saveDescriptionButton: 'vn-ticket-service > vn-dialog[vn-id="createServiceTypeDialog"] > div > form > div.buttons > tpl-buttons > button' + saveDescriptionButton: '.vn-dialog.shown tpl-buttons > button' }, createStateView: { stateAutocomplete: 'vn-autocomplete[ng-model="$ctrl.stateFk"]', @@ -522,8 +522,8 @@ export default { }, claimDescriptor: { moreMenu: 'vn-claim-descriptor vn-icon-menu[icon=more_vert]', - moreMenuDeleteClaim: '.vn-popover.shown .vn-drop-down li[name="Delete claim"]', - acceptDeleteClaim: 'vn-claim-descriptor > vn-confirm[vn-id="confirm-delete-claim"] button[response="ACCEPT"]' + moreMenuDeleteClaim: '.vn-drop-down.shown li[name="Delete claim"]', + acceptDeleteClaim: '.vn-confirm.shown button[response="ACCEPT"]' }, claimSummary: { header: 'vn-claim-summary > vn-card > h5', @@ -549,7 +549,7 @@ export default { discountInput: '.vn-popover.shown vn-input-number[ng-model="$ctrl.newDiscount"] input', discoutPopoverMana: '.vn-popover.shown .content > div > vn-horizontal > h5', addItemButton: 'vn-claim-detail a vn-float-button', - firstClaimableSaleFromTicket: 'vn-claim-detail > vn-dialog vn-tbody > vn-tr', + firstClaimableSaleFromTicket: '.vn-dialog.shown vn-tbody > vn-tr', claimDetailLine: 'vn-claim-detail > vn-vertical > vn-card > vn-vertical > vn-table > div > vn-tbody > vn-tr', firstItemQuantityInput: 'vn-claim-detail vn-tr:nth-child(1) vn-input-number[ng-model="saleClaimed.quantity"] input', totalClaimed: 'vn-claim-detail > vn-vertical > vn-card > vn-vertical > vn-horizontal > div > vn-label-value:nth-child(2) > section > span', @@ -589,7 +589,7 @@ export default { }, orderDescriptor: { returnToModuleIndexButton: 'vn-order-descriptor a[ui-sref="order.index"]', - acceptNavigationButton: 'vn-order-basic-data vn-confirm button[response=ACCEPT]' + acceptNavigationButton: '.vn-confirm.shown button[response=ACCEPT]' }, createOrderView: { clientAutocomplete: 'vn-autocomplete[label="Client"]', @@ -618,13 +618,13 @@ export default { agencyAutocomplete: 'vn-autocomplete[label="Agency"]', observationInput: 'vn-textarea[label="Observation"] textarea', saveButton: `button[type=submit]`, - acceptButton: 'vn-order-basic-data vn-confirm[vn-id="confirm"] button[response="ACCEPT"]' + acceptButton: '.vn-confirm.shown button[response="ACCEPT"]' }, orderLine: { - orderSubtotal: 'vn-order-line vn-horizontal.header p:nth-child(1)', + orderSubtotal: 'vn-order-line .header :first-child', firstLineDeleteButton: 'vn-order-line vn-tbody > vn-tr:nth-child(1) vn-icon[icon="delete"]', - confirmOrder: 'vn-order-line > vn-vertical > vn-button-bar > vn-button > button', - confirmButton: 'vn-order-line > vn-confirm button[response="ACCEPT"]', + confirmOrder: 'vn-order-line vn-float-button', + confirmButton: '.vn-confirm.shown button[response="ACCEPT"]', }, routeIndex: { addNewRouteButton: 'vn-route-index > a[ui-sref="route.create"]' @@ -663,7 +663,7 @@ export default { firstTicketCheckbox: 'vn-route-tickets vn-tr:nth-child(1) vn-check', buscamanButton: 'vn-route-tickets vn-button[icon="icon-buscaman"]', firstTicketDeleteButton: 'vn-route-tickets vn-tr:nth-child(1) vn-icon[icon="delete"]', - confirmButton: 'vn-route-tickets > vn-confirm button[response="ACCEPT"]' + confirmButton: '.vn-confirm.shown button[response="ACCEPT"]' }, workerPbx: { extensionInput: 'vn-worker-pbx vn-textfield[ng-model="$ctrl.worker.sip.extension"] input', @@ -678,7 +678,7 @@ export default { fridayAddTimeButton: 'vn-worker-time-control vn-table > div > vn-tfoot > vn-tr:nth-child(2) > vn-td:nth-child(5) > vn-icon-button', saturdayAddTimeButton: 'vn-worker-time-control vn-table > div > vn-tfoot > vn-tr:nth-child(2) > vn-td:nth-child(6) > vn-icon-button', sundayAddTimeButton: 'vn-worker-time-control vn-table > div > vn-tfoot > vn-tr:nth-child(2) > vn-td:nth-child(7) > vn-icon-button', - confirmButton: 'vn-worker-time-control > vn-dialog > div > form > div.buttons > tpl-buttons > button', + confirmButton: '.vn-dialog.shown tpl-buttons > button', firstEntryOfMonday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(1) > section:nth-child(1) > span', firstEntryOfTuesday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(2) > section:nth-child(1) > span', firstEntryOfWednesday: 'vn-worker-time-control vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(3) > section:nth-child(1) > span', @@ -726,11 +726,11 @@ export default { }, invoiceOutDescriptor: { moreMenu: 'vn-invoice-out-descriptor vn-icon-menu[icon=more_vert]', - moreMenuDeleteInvoiceOut: '.vn-popover.shown .vn-drop-down li[name="Delete Invoice"]', - moreMenuBookInvoiceOut: '.vn-popover.shown .vn-drop-down li[name="Book invoice"]', - moreMenuShowInvoiceOutPdf: '.vn-popover.shown .vn-drop-down li[name="Show invoice PDF"]', - acceptDeleteButton: 'vn-invoice-out-descriptor > vn-confirm[vn-id="deleteConfirmation"] button[response="ACCEPT"]', - acceptBookingButton: 'vn-invoice-out-descriptor > vn-confirm[vn-id="bookConfirmation"] button[response="ACCEPT"]' + moreMenuDeleteInvoiceOut: '.vn-drop-down.shown li[name="Delete Invoice"]', + moreMenuBookInvoiceOut: '.vn-drop-down.shown li[name="Book invoice"]', + moreMenuShowInvoiceOutPdf: '.vn-drop-down.shown li[name="Show invoice PDF"]', + acceptDeleteButton: '.vn-confirm.shown button[response="ACCEPT"]', + acceptBookingButton: '.vn-confirm.shown button[response="ACCEPT"]' }, invoiceOutSummary: { bookedLabel: 'vn-invoice-out-summary > vn-card > vn-horizontal > vn-one > vn-label-value:nth-child(4) > section > span' diff --git a/e2e/paths/01-login/01_login.spec.js b/e2e/paths/01-login/01_login.spec.js index 03acc98a8..e9e64c311 100644 --- a/e2e/paths/01-login/01_login.spec.js +++ b/e2e/paths/01-login/01_login.spec.js @@ -6,6 +6,7 @@ describe('Login path', () => { it('should receive an error when the username is incorrect', async() => { const result = await nightmare .doLogin('badUser', null) + .waitUntilNotPresent('body', 'jose') .waitForLastSnackbar(); expect(result.length).toBeGreaterThan(0); diff --git a/e2e/paths/02-client-module/05_add_address.spec.js b/e2e/paths/02-client-module/05_add_address.spec.js index f4e68634a..9134642a8 100644 --- a/e2e/paths/02-client-module/05_add_address.spec.js +++ b/e2e/paths/02-client-module/05_add_address.spec.js @@ -110,7 +110,7 @@ describe('Client Add address path', () => { it(`should go back to the addreses section by clicking the cancel button`, async() => { const url = await nightmare .waitToClick(selectors.clientAddresses.cancelEditAddressButton) - .waitToClick('vn-confirm button[response="ACCEPT"]') + .waitToClick('.vn-confirm.shown button[response="ACCEPT"]') .waitForURL('address/index') .parsedUrl(); diff --git a/e2e/paths/04-item-module/01_summary.spec.js b/e2e/paths/04-item-module/01_summary.spec.js index 25e442feb..bd06ebef4 100644 --- a/e2e/paths/04-item-module/01_summary.spec.js +++ b/e2e/paths/04-item-module/01_summary.spec.js @@ -21,16 +21,12 @@ describe('Item summary path', () => { }); it(`should click on the search result summary button to open the item summary popup`, async() => { - const isVisibleBefore = await nightmare + const isVisible = await nightmare .waitForTextInElement(selectors.itemsIndex.searchResult, 'Ranged weapon longbow 2m') - .isVisible(selectors.itemSummary.basicData); - - const isVisibleAfter = await nightmare .waitToClick(selectors.itemsIndex.searchResultPreviewButton) .isVisible(selectors.itemSummary.basicData); - expect(isVisibleBefore).toBeFalsy(); - expect(isVisibleAfter).toBeTruthy(); + expect(isVisible).toBeTruthy(); }); it(`should check the item summary preview shows fields from basic data`, async() => { @@ -75,8 +71,9 @@ describe('Item summary path', () => { it(`should close the summary popup`, async() => { const result = await nightmare - .waitToClick(selectors.itemsIndex.closeItemSummaryPreview) - .isVisible(selectors.itemSummary.basicData); + .mousedown(selectors.itemsIndex.closeItemSummaryPreview) + .waitUntilNotPresent(selectors.itemSummary.basicData) + .visible(selectors.itemSummary.basicData); expect(result).toBeFalsy(); }); @@ -94,17 +91,13 @@ describe('Item summary path', () => { }); it(`should now click on the search result summary button to open the item summary popup`, async() => { - const isVisibleBefore = await nightmare + const isVisible = await nightmare .waitForTextInElement(selectors.itemsIndex.searchResult, 'Melee weapon combat fist 15cm') - .isVisible(selectors.itemSummary.basicData); - - const isVisibleAfter = await nightmare .waitToClick(selectors.itemsIndex.searchResultPreviewButton) .isVisible(selectors.itemSummary.basicData); - expect(isVisibleBefore).toBeFalsy(); - expect(isVisibleAfter).toBeTruthy(); + expect(isVisible).toBeTruthy(); }); it(`should now check the item summary preview shows fields from basic data`, async() => { @@ -149,8 +142,9 @@ describe('Item summary path', () => { it(`should now close the summary popup`, async() => { const result = await nightmare - .waitToClick(selectors.itemsIndex.closeItemSummaryPreview) - .isVisible(selectors.itemSummary.basicData); + .mousedown(selectors.itemsIndex.closeItemSummaryPreview) + .waitUntilNotPresent(selectors.itemSummary.basicData) + .visible(selectors.itemSummary.basicData); expect(result).toBeFalsy(); }); diff --git a/e2e/paths/05-ticket-module/13_services.spec.js b/e2e/paths/05-ticket-module/13_services.spec.js index 7172ab5a6..dbce6ea6e 100644 --- a/e2e/paths/05-ticket-module/13_services.spec.js +++ b/e2e/paths/05-ticket-module/13_services.spec.js @@ -65,7 +65,7 @@ describe('Ticket services path', () => { it('should click on the add new description to open the dialog', async() => { const result = await nightmare .waitToClick(selectors.ticketService.firstAddDescriptionButton) - .waitForClassPresent('vn-ticket-service > vn-dialog', 'shown') + .wait('.vn-dialog.shown') .isVisible(selectors.ticketService.newDescriptionInput); expect(result).toBeTruthy(); diff --git a/front/core/components/array-model/array-model.js b/front/core/components/array-model/array-model.js index 3697abc3b..5b0b94cdc 100644 --- a/front/core/components/array-model/array-model.js +++ b/front/core/components/array-model/array-model.js @@ -100,7 +100,7 @@ export default class ArrayModel extends ModelProxy { addFilter(user, params) { this.userFilter = this.mergeFilters(user, this.userFilter); - Object.assign(this.userParams, params); + this.userParams = Object.assign({}, this.userParams, params); return this.refresh(); } diff --git a/front/core/components/autocomplete/index.html b/front/core/components/autocomplete/index.html index b51090f48..725d38977 100755 --- a/front/core/components/autocomplete/index.html +++ b/front/core/components/autocomplete/index.html @@ -26,7 +26,7 @@ ng-click="$ctrl.onClear($event)"> diff --git a/front/core/components/autocomplete/index.js b/front/core/components/autocomplete/index.js index d2fdce16a..9808fd667 100755 --- a/front/core/components/autocomplete/index.js +++ b/front/core/components/autocomplete/index.js @@ -17,14 +17,9 @@ import './style.scss'; * @event change Thrown when value is changed */ export default class Autocomplete extends Field { - constructor($element, $scope, $compile, $http, $transclude, $translate, $interpolate) { - super($element, $scope, $compile); - Object.assign(this, { - $http, - $interpolate, - $transclude, - $translate - }); + constructor($element, $, $compile, $transclude) { + super($element, $, $compile); + this.$transclude = $transclude; this._selection = null; this.input = this.element.querySelector('input'); @@ -48,7 +43,6 @@ export default class Autocomplete extends Field { set field(value) { super.field = value; this.refreshSelection(); - this.emit('change', {value}); } get model() { @@ -121,7 +115,6 @@ export default class Autocomplete extends Field { return; const selection = this.fetchSelection(); - this.selection = selection; } @@ -206,7 +199,7 @@ export default class Autocomplete extends Field { onDropDownSelect(item) { const value = item[this.valueField]; this.selection = item; - this.field = value; + this.change(value); } onDropDownClose() { @@ -216,7 +209,7 @@ export default class Autocomplete extends Field { onContainerKeyDown(event) { if (event.defaultPrevented) return; - switch (event.code) { + switch (event.key) { case 'ArrowUp': case 'ArrowDown': case 'Enter': @@ -241,12 +234,13 @@ export default class Autocomplete extends Field { assignDropdownProps() { if (!this.$.dropDown) return; + this.$.dropDown.copySlot('tplItem', this.$transclude); + assignProps(this, this.$.dropDown, [ 'valueField', 'showField', 'showFilter', 'multiple', - '$transclude', 'translateFields', 'model', 'data', @@ -277,7 +271,7 @@ export default class Autocomplete extends Field { this.refreshSelection(); } } -Autocomplete.$inject = ['$element', '$scope', '$compile', '$http', '$transclude', '$translate', '$interpolate']; +Autocomplete.$inject = ['$element', '$scope', '$compile', '$transclude']; ngModule.vnComponent('vnAutocomplete', { template: require('./index.html'), diff --git a/front/core/components/autocomplete/style.scss b/front/core/components/autocomplete/style.scss index 6be42c3bc..19e8362d5 100755 --- a/front/core/components/autocomplete/style.scss +++ b/front/core/components/autocomplete/style.scss @@ -1,6 +1,6 @@ @import "effects"; -vn-autocomplete.vn-field { +.vn-autocomplete { overflow: hidden; & > .container { diff --git a/front/core/components/button-menu/index.js b/front/core/components/button-menu/index.js index e9fb8d565..946e1fd7f 100644 --- a/front/core/components/button-menu/index.js +++ b/front/core/components/button-menu/index.js @@ -55,12 +55,13 @@ export default class ButtonMenu extends Button { } showDropDown() { + this.$.dropDown.copySlot('tplItem', this.$transclude); + assignProps(this, this.$.dropDown, [ 'valueField', 'showField', 'showFilter', 'multiple', - '$transclude', 'translateFields', 'model', 'data', diff --git a/front/core/components/button-menu/style.scss b/front/core/components/button-menu/style.scss index 1cd995b15..cbb6129bd 100644 --- a/front/core/components/button-menu/style.scss +++ b/front/core/components/button-menu/style.scss @@ -1,3 +1,3 @@ -vn-button-menu { +.vn-button-menu { position: relative; } \ No newline at end of file diff --git a/front/core/components/button/index.js b/front/core/components/button/index.js index 19b102274..17710967a 100644 --- a/front/core/components/button/index.js +++ b/front/core/components/button/index.js @@ -7,7 +7,6 @@ export default class Button extends FormInput { super($element, $scope); this.design = 'colored'; this.initTabIndex(); - this.classList.add('vn-button'); this.element.addEventListener('keyup', e => this.onKeyup(e)); this.element.addEventListener('click', e => this.onClick(e)); } @@ -19,8 +18,8 @@ export default class Button extends FormInput { onKeyup(event) { if (event.defaultPrevented) return; - switch (event.code) { - case 'Space': + switch (event.key) { + case ' ': case 'Enter': return this.element.click(); } diff --git a/front/core/components/calendar/index.js b/front/core/components/calendar/index.js index 6a56ed86a..4afec0a9a 100644 --- a/front/core/components/calendar/index.js +++ b/front/core/components/calendar/index.js @@ -129,7 +129,7 @@ export default class Calendar extends FormInput { */ select(day) { if (!this.editable) return; - this.field = day; + this.change(day); this.emit('selection', { $days: [day], $type: 'day' diff --git a/front/core/components/calendar/style.scss b/front/core/components/calendar/style.scss index b00c40648..8492d09f1 100644 --- a/front/core/components/calendar/style.scss +++ b/front/core/components/calendar/style.scss @@ -1,6 +1,6 @@ @import "variables"; -vn-calendar { +.vn-calendar { display: block; & > div { diff --git a/front/core/components/check/index.js b/front/core/components/check/index.js index b9bd1bb2f..78b1807a5 100644 --- a/front/core/components/check/index.js +++ b/front/core/components/check/index.js @@ -49,18 +49,19 @@ export default class Check extends Toggle { onClick(event) { if (super.onClick(event)) return; + let value; if (this.tripleState) { if (this.field == null) - this.field = true; + value = true; else if (this.field) - this.field = false; + value = false; else - this.field = null; + value = null; } else - this.field = !this.field; + value = !this.field; - this.changed(); + this.change(value); } } diff --git a/front/core/components/check/style.scss b/front/core/components/check/style.scss index f292e45f9..31715a2cd 100644 --- a/front/core/components/check/style.scss +++ b/front/core/components/check/style.scss @@ -1,6 +1,6 @@ @import "variables"; -vn-check { +.vn-check { & > .btn { border-radius: 2px; transition: background 250ms; @@ -12,8 +12,13 @@ vn-check { border-width: 0; } } + & > vn-icon { + margin-left: 5px; + color: $color-font-secondary; + vertical-align: middle; + } &.checked > .btn { - border-color: $color-main; + border-color: transparent; background-color: $color-main; & > .mark { @@ -35,9 +40,7 @@ vn-check { height: 2px; border-bottom: 2px solid #666; } - & > vn-icon { - margin-left: 5px; - color: $color-font-secondary; - vertical-align: middle; + &.disabled.checked > .btn { + background-color: $color-font-secondary; } } diff --git a/front/core/components/chip/index.js b/front/core/components/chip/index.js index 6a945559b..6cffecc2b 100644 --- a/front/core/components/chip/index.js +++ b/front/core/components/chip/index.js @@ -9,7 +9,7 @@ export default class Chip extends Component { } Chip.$inject = ['$element', '$scope', '$transclude']; -ngModule.component('vnChip', { +ngModule.vnComponent('vnChip', { template: require('./index.html'), controller: Chip, transclude: true, diff --git a/front/core/components/confirm/confirm.js b/front/core/components/confirm/confirm.js index 8b27d8295..9d53df798 100644 --- a/front/core/components/confirm/confirm.js +++ b/front/core/components/confirm/confirm.js @@ -7,13 +7,8 @@ export default class Confirm extends Dialog { super($element, $, $transclude); let $template = angular.element(template); - let slots = $transclude.$$boundTransclude.$$slots; - - let bodyLinkFn = this.$compile($template.find('tpl-body')); - slots.body = this.createBoundTranscludeFn(bodyLinkFn); - - let buttonsLinkFn = this.$compile($template.find('tpl-buttons')); - slots.buttons = this.createBoundTranscludeFn(buttonsLinkFn); + this.fillSlot('body', $template.find('tpl-body')); + this.fillSlot('buttons', $template.find('tpl-buttons')); } } diff --git a/front/core/components/crud-model/crud-model.js b/front/core/components/crud-model/crud-model.js index 41b5390a7..9a260a690 100644 --- a/front/core/components/crud-model/crud-model.js +++ b/front/core/components/crud-model/crud-model.js @@ -95,7 +95,7 @@ export default class CrudModel extends ModelProxy { */ addFilter(filter, params) { this.userFilter = mergeFilters(filter, this.userFilter); - Object.assign(this.userParams, params); + this.userParams = Object.assign({}, this.userParams, params); return this.refresh(); } diff --git a/front/core/components/date-picker/index.js b/front/core/components/date-picker/index.js index b667674fa..17ce19406 100644 --- a/front/core/components/date-picker/index.js +++ b/front/core/components/date-picker/index.js @@ -1,12 +1,9 @@ import ngModule from '../../module'; import Field from '../field'; -import './style.scss'; class DatePicker extends Field { - constructor($element, $scope, $compile, $translate, $filter) { + constructor($element, $scope, $compile) { super($element, $scope, $compile); - this.$translate = $translate; - this.$filter = $filter; this.input = $compile(``)($scope)[0]; this.input.addEventListener('change', () => this.onValueUpdate()); @@ -46,7 +43,7 @@ class DatePicker extends Field { this.input.value = this.$filter('date')(value, 'yyyy-MM-dd'); } } -DatePicker.$inject = ['$element', '$scope', '$compile', '$translate', '$filter']; +DatePicker.$inject = ['$element', '$scope', '$compile']; ngModule.vnComponent('vnDatePicker', { controller: DatePicker, diff --git a/front/core/components/date-picker/style.scss b/front/core/components/date-picker/style.scss deleted file mode 100644 index 6af4580f6..000000000 --- a/front/core/components/date-picker/style.scss +++ /dev/null @@ -1,7 +0,0 @@ -@import "variables"; - -.flatpickr-months .flatpickr-month, -.flatpickr-weekdays, -span.flatpickr-weekday { - background-color: $color-main; -} diff --git a/front/core/components/dialog/index.js b/front/core/components/dialog/index.js index 8bc3dfc85..5415a906b 100644 --- a/front/core/components/dialog/index.js +++ b/front/core/components/dialog/index.js @@ -12,16 +12,14 @@ import './style.scss'; export default class Dialog extends Popup { constructor($element, $, $transclude) { super($element, $, $transclude); - - let linkFn = this.$compile(template); - $transclude.$$boundTransclude = this.createBoundTranscludeFn(linkFn); + this.fillDefaultSlot(template); } /** * Hides the dialog calling the response handler. */ hide() { - // this.fireResponse(); + this.fireResponse(); super.hide(); } diff --git a/front/core/components/dialog/index.spec.js b/front/core/components/dialog/index.spec.js index b889f1bc0..ce7582399 100644 --- a/front/core/components/dialog/index.spec.js +++ b/front/core/components/dialog/index.spec.js @@ -4,31 +4,12 @@ describe('Component vnDialog', () => { beforeEach(ngModule('vnCore')); - beforeEach(angular.mock.inject($componentController => { - $element = angular.element(''); - controller = $componentController('vnDialog', {$element, $transclude: null}); + beforeEach(angular.mock.inject(($rootScope, $compile) => { + $element = $compile('Body')($rootScope); + controller = $element.controller('vnDialog'); controller.emit = jasmine.createSpy('emit'); })); - describe('show()', () => { - it(`should do nothing if controller.shown is defined`, () => { - controller.element = {style: {display: 'none'}}; - controller.shown = true; - controller.show(); - - expect(controller.element.style.display).toEqual('none'); - expect(controller.emit).not.toHaveBeenCalledWith('open'); - }); - - it(`should set shown on the controller, set style.display on the element and emit onOpen() event`, () => { - controller.show(); - - expect(controller.element.style.display).toEqual('flex'); - expect(controller.shown).toBeTruthy(); - expect(controller.emit).toHaveBeenCalledWith('open'); - }); - }); - describe('hide()', () => { describe('fireResponse()', () => { it(`should call onResponse() if it's defined in the controller`, () => { @@ -51,23 +32,5 @@ describe('Component vnDialog', () => { expect(responseRet).toEqual(false); }); }); - - describe('realHide()', () => { - it(`should do nothing if controller.shown is not defined`, () => { - controller.element = {style: {display: 'not none'}}; - controller.hide(); - - expect(controller.element.style.display).toEqual('not none'); - }); - - it(`should set lastEvent, shown and element.style.display to their expected values`, () => { - controller.shown = true; - controller.hide(); - - expect(controller.lastEvent).toBeFalsy(); - expect(controller.shown).toBeFalsy(); - expect(controller.element.style.display).toEqual('none'); - }); - }); }); }); diff --git a/front/core/components/drop-down/drop-down.html b/front/core/components/drop-down/drop-down.html deleted file mode 100755 index 2e4db921d..000000000 --- a/front/core/components/drop-down/drop-down.html +++ /dev/null @@ -1,31 +0,0 @@ - -
-
- - -
-
- -
- {{$ctrl.statusText}} -
-
-
-
diff --git a/front/core/components/drop-down/index.html b/front/core/components/drop-down/index.html new file mode 100755 index 000000000..5366d9d90 --- /dev/null +++ b/front/core/components/drop-down/index.html @@ -0,0 +1,21 @@ +
+ + +
+
+ +
+ {{$ctrl.statusText}} +
+
\ No newline at end of file diff --git a/front/core/components/drop-down/drop-down.js b/front/core/components/drop-down/index.js similarity index 85% rename from front/core/components/drop-down/drop-down.js rename to front/core/components/drop-down/index.js index 84313814c..163553aeb 100755 --- a/front/core/components/drop-down/drop-down.js +++ b/front/core/components/drop-down/index.js @@ -1,6 +1,7 @@ import './style.scss'; import ngModule from '../../module'; -import Component from '../../lib/component'; +import Popover from '../popover'; +import template from './index.html'; import ArrayModel from '../array-model/array-model'; import CrudModel from '../crud-model/crud-model'; import {mergeWhere} from 'vn-loopback/util/filter'; @@ -9,34 +10,17 @@ import {mergeWhere} from 'vn-loopback/util/filter'; * @event select Thrown when model item is selected * @event change Thrown when model data is ready */ -export default class DropDown extends Component { - constructor($element, $scope, $transclude, $timeout, $translate, $http, $q, $filter) { - super($element, $scope); - this.$transclude = $transclude; - this.$timeout = $timeout; - this.$translate = $translate; - this.$http = $http; - this.$q = $q; - this.$filter = $filter; - +export default class DropDown extends Popover { + constructor($element, $, $transclude) { + super($element, $, $transclude); this.valueField = 'id'; this.showField = 'name'; this._search = undefined; this._activeOption = -1; this.showLoadMore = true; this.showFilter = true; - } - - $postLink() { - super.$postLink(); - } - - get shown() { - return this.$.popover && this.$.popover.shown; - } - - set shown(value) { - this.$.popover.shown = value; + this.searchDelay = 300; + this.fillDefaultSlot(template); } get search() { @@ -64,7 +48,7 @@ export default class DropDown extends Component { this.searchTimeout = this.$timeout(() => { this.refreshModel(); this.searchTimeout = null; - }, 350); + }, value != null ? this.searchDelay : 0); } else this.refreshModel(); } @@ -103,16 +87,37 @@ export default class DropDown extends Component { */ show(parent, search) { this._activeOption = -1; - this.$.popover.show(parent || this.parent); + super.show(parent); + + this.list = this.popup.querySelector('.list'); + this.ul = this.popup.querySelector('ul'); + + this.docKeyDownHandler = e => this.onDocKeyDown(e); + this.document.addEventListener('keydown', this.docKeyDownHandler); + + this.listScrollHandler = e => this.onScroll(e); + this.list.addEventListener('scroll', this.listScrollHandler); + this.list.scrollTop = 0; + this.search = search; this.buildList(); + + let input = this.popup.querySelector('input'); + setTimeout(() => input.focus()); } - /** - * Hides the drop-down. - */ - hide() { - this.$.popover.hide(); + onClose() { + this.document.removeEventListener('keydown', this.docKeyDownHandler); + this.docKeyDownHandler = null; + + this.list.removeEventListener('scroll', this.listScrollHandler); + this.listScrollHandler = null; + + this.list = null; + this.ul = null; + + this.destroyList(); + super.onClose(); } /** @@ -123,7 +128,7 @@ export default class DropDown extends Component { moveToOption(option) { this.activateOption(option); - let list = this.$.list; + let list = this.list; let li = this.activeLi; if (!li) return; @@ -150,7 +155,7 @@ export default class DropDown extends Component { let data = this.modelData; if (option >= 0 && data && option < data.length) { - this.activeLi = this.$.ul.children[option]; + this.activeLi = this.ul.children[option]; this.activeLi.className = 'active'; } } @@ -184,29 +189,7 @@ export default class DropDown extends Component { } if (!this.multiple) - this.$.popover.hide(); - } - - onOpen() { - this.docKeyDownHandler = e => this.onDocKeyDown(e); - this.document.addEventListener('keydown', this.docKeyDownHandler); - - this.listScrollHandler = e => this.onScroll(e); - this.$.list.addEventListener('scroll', this.listScrollHandler); - this.$.list.scrollTop = 0; - - setTimeout(() => this.$.input.focus()); - this.emit('open'); - } - - onClose() { - this.document.removeEventListener('keydown', this.docKeyDownHandler); - this.docKeyDownHandler = null; - - this.$.list.removeEventListener('scroll', this.listScrollHandler); - this.listScrollHandler = null; - - this.emit('close'); + this.hide(); } onClearClick() { @@ -214,7 +197,7 @@ export default class DropDown extends Component { } onScroll() { - let list = this.$.list; + let list = this.list; let shouldLoad = list.scrollTop + list.clientHeight >= (list.scrollHeight - 40) && !this.model.isLoading; @@ -230,9 +213,8 @@ export default class DropDown extends Component { onContainerClick(event) { if (event.defaultPrevented) return; - let index = getPosition(this.$.ul, event); - if (index != -1) - this.selectOption(index); + let index = getPosition(this.ul, event); + if (index != -1) this.selectOption(index); } onDocKeyDown(event) { @@ -242,23 +224,23 @@ export default class DropDown extends Component { let option = this.activeOption; let nOpts = data ? data.length - 1 : 0; - switch (event.keyCode) { - case 9: // Tab + switch (event.key) { + case 'Tab': this.selectOption(option); return; - case 13: // Enter + case 'Enter': this.selectOption(option); break; - case 38: // Up + case 'ArrowUp': this.moveToOption(option <= 0 ? nOpts : option - 1); break; - case 40: // Down + case 'ArrowDown': this.moveToOption(option >= nOpts ? 0 : option + 1); break; - case 35: // End + case 'End': this.moveToOption(nOpts); break; - case 36: // Start + case 'Home': this.moveToOption(0); break; default: @@ -315,13 +297,14 @@ export default class DropDown extends Component { } } - this.$.ul.appendChild(fragment); + this.ul.appendChild(fragment); this.activateOption(this._activeOption); - this.$.$applyAsync(() => this.$.popover.relocate()); + this.$.$applyAsync(() => this.relocate()); } destroyList() { - this.$.ul.innerHTML = ''; + if (this.ul) + this.ul.innerHTML = ''; if (this.scopes) { for (let scope of this.scopes) @@ -344,10 +327,6 @@ export default class DropDown extends Component { return fields; } - $onDestroy() { - this.destroyList(); - } - // Model related code onDataChange() { @@ -436,7 +415,6 @@ export default class DropDown extends Component { return {[this.showField]: scope.$search}; } } -DropDown.$inject = ['$element', '$scope', '$transclude', '$timeout', '$translate', '$http', '$q', '$filter']; /** * Gets the position of an event element relative to a parent. @@ -463,9 +441,11 @@ function getPosition(parent, event) { return -1; } -ngModule.component('vnDropDown', { - template: require('./drop-down.html'), +ngModule.vnComponent('vnDropDown', { controller: DropDown, + transclude: { + tplItem: '?tplItem' + }, bindings: { field: '=?', selection: '=?', @@ -482,9 +462,7 @@ ngModule.component('vnDropDown', { where: ' .window > .content { display: flex; flex-direction: column; height: inherit; diff --git a/front/core/components/field/index.html b/front/core/components/field/index.html index c2e7a02c2..8d12ddd77 100644 --- a/front/core/components/field/index.html +++ b/front/core/components/field/index.html @@ -19,7 +19,7 @@ ng-click="$ctrl.onClear($event)"> diff --git a/front/core/components/field/index.js b/front/core/components/field/index.js index 9382aaa95..cd9da4cec 100644 --- a/front/core/components/field/index.js +++ b/front/core/components/field/index.js @@ -11,7 +11,6 @@ export default class Field extends FormInput { this.suffix = null; this.control = this.element.querySelector('.control'); - this.classList.add('vn-field'); this.element.addEventListener('click', e => this.onClick(e)); this.container = this.element.querySelector('.container'); @@ -25,9 +24,7 @@ export default class Field extends FormInput { this.input.addEventListener('focus', () => this.onFocus(true)); this.input.addEventListener('blur', () => this.onFocus(false)); - this.input.addEventListener('change', e => { - this.emit('change', {event: e}); - }); + this.input.addEventListener('change', () => this.onChange()); } set field(value) { @@ -172,6 +169,7 @@ export default class Field extends FormInput { onClear(event) { if (event.defaultPrevented) return; + event.preventDefault(); this.field = null; this.input.dispatchEvent(new Event('change')); } @@ -193,6 +191,10 @@ export default class Field extends FormInput { this.inputError = error; this.refreshHint(); } + + onChange() { + this.emit('change', {value: this.field}); + } } Field.$inject = ['$element', '$scope', '$compile']; diff --git a/front/core/components/field/style.scss b/front/core/components/field/style.scss index e57b27912..add3a3228 100644 --- a/front/core/components/field/style.scss +++ b/front/core/components/field/style.scss @@ -35,7 +35,7 @@ & > .fix { padding-top: 24px; line-height: 24px; - font-size: $font-size; + font-size: 1rem; opacity: 0; transition: opacity 200ms ease-in-out; @@ -58,7 +58,7 @@ border: none; font-family: Arial, sans-serif; display: block; - font-size: $font-size; + font-size: 1rem; width: 100%; background: 0; color: inherit; diff --git a/front/core/components/form-input/index.js b/front/core/components/form-input/index.js index 3d22b290c..0395922c7 100644 --- a/front/core/components/form-input/index.js +++ b/front/core/components/form-input/index.js @@ -12,6 +12,7 @@ export default class FormInput extends Component { constructor($element, $scope) { super($element, $scope); this.classList = this.element.classList; + this.classList.add(...this.constructor.$classNames); } $onInit() { @@ -104,6 +105,12 @@ export default class FormInput extends Component { refreshTabIndex() { this.inputEl.tabIndex = this.disabled ? -1 : this.tabIndex; } + + change(value) { + this.field = value; + this.element.dispatchEvent(new Event('change')); + this.emit('change', {value: this.field}); + } } ngModule.vnComponent('vnFormInput', { diff --git a/front/core/components/icon-button/style.scss b/front/core/components/icon-button/style.scss index c73580ad9..1126c5e6d 100644 --- a/front/core/components/icon-button/style.scss +++ b/front/core/components/icon-button/style.scss @@ -1,6 +1,6 @@ @import "effects"; -vn-icon-button { +.vn-icon-button { @extend %clickable-light; color: $color-main; diff --git a/front/core/components/icon-menu/index.js b/front/core/components/icon-menu/index.js index 0549149a8..6dd3d683a 100644 --- a/front/core/components/icon-menu/index.js +++ b/front/core/components/icon-menu/index.js @@ -2,8 +2,8 @@ import ngModule from '../../module'; import ButtonMenu from '../button-menu'; export default class IconMenu extends ButtonMenu { - constructor($element, $scope) { - super($element, $scope); + constructor($element, $scope, $transclude) { + super($element, $scope, $transclude); this.element.classList.add('flat'); } } diff --git a/front/core/components/index.js b/front/core/components/index.js index d59da46ea..bc19db642 100644 --- a/front/core/components/index.js +++ b/front/core/components/index.js @@ -9,8 +9,6 @@ import './subtitle/subtitle'; import './spinner/spinner'; import './snackbar/snackbar'; import './tooltip/tooltip'; -import './popover/popover'; -import './drop-down/drop-down'; import './menu/menu'; import './multi-check/multi-check'; import './card/card'; @@ -26,6 +24,7 @@ import './check'; import './chip'; import './data-viewer'; import './date-picker'; +import './drop-down'; import './debug-info'; import './dialog'; import './field'; @@ -39,6 +38,7 @@ import './input-time'; import './input-file'; import './label'; import './list'; +import './popover'; import './popup'; import './radio'; import './submit'; diff --git a/front/core/components/input-number/index.html b/front/core/components/input-number/index.html index ee6f50397..2c6f7d824 100644 --- a/front/core/components/input-number/index.html +++ b/front/core/components/input-number/index.html @@ -19,7 +19,7 @@ ng-click="$ctrl.onClear($event)"> diff --git a/front/core/components/menu/menu.js b/front/core/components/menu/menu.js index ff54d55d4..3eb169926 100755 --- a/front/core/components/menu/menu.js +++ b/front/core/components/menu/menu.js @@ -1,20 +1,13 @@ import ngModule from '../../module'; -import Popover from '../popover/popover'; +import Popover from '../popover'; export default class Menu extends Popover { - $postLink() { - super.$postLink(); - this.popover.addEventListener('click', - () => this.hide()); + show(parent) { + super.show(parent); + this.windowEl.addEventListener('click', () => this.hide()); } } -ngModule.component('vnMenu', { - template: require('../popover/popover.html'), - controller: Menu, - transclude: true, - bindings: { - onOpen: '&?', - onClose: '&?' - } +ngModule.vnComponent('vnMenu', { + controller: Menu }); diff --git a/front/core/components/multi-check/style.scss b/front/core/components/multi-check/style.scss index b1e3d9432..bc6a0e8c5 100644 --- a/front/core/components/multi-check/style.scss +++ b/front/core/components/multi-check/style.scss @@ -1,5 +1,5 @@ vn-multi-check { - vn-check { + .vn-check { margin-bottom: 0.8em } } \ No newline at end of file diff --git a/front/core/components/popover/index.html b/front/core/components/popover/index.html new file mode 100644 index 000000000..de916e3b4 --- /dev/null +++ b/front/core/components/popover/index.html @@ -0,0 +1,8 @@ +
+
+
+
+
+
\ No newline at end of file diff --git a/front/core/components/popover/index.js b/front/core/components/popover/index.js new file mode 100644 index 000000000..413f4d85f --- /dev/null +++ b/front/core/components/popover/index.js @@ -0,0 +1,101 @@ +import ngModule from '../../module'; +import Popup from '../popup'; +import template from './index.html'; +import isMobile from '../../lib/is-mobile'; +import './style.scss'; + +/** + * A simple popover. + * + * @property {HTMLElement} parent The parent element to show drop down relative to + * + * @event open Thrown when popover is displayed + * @event close Thrown when popover is hidden + */ +export default class Popover extends Popup { + constructor($element, $, $transclude) { + super($element, $, $transclude); + this.displayMode = isMobile ? 'centered' : 'relative'; + this.template = template; + } + + /** + * Shows the popover emitting the open signal. If a parent is specified + * it is shown in a visible relative position to it. + * + * @param {HTMLElement} parent Overrides the parent property + */ + show(parent) { + if (parent) this.parent = parent; + super.show(); + this.content = this.popup.querySelector('.content'); + this.$timeout(() => this.relocate(), 10); + } + + hide() { + this.content = null; + super.hide(); + } + + /** + * Repositions the popover to a correct location relative to the parent. + */ + relocate() { + if (!(this.parent && this._shown && this.displayMode == 'relative')) + return; + + let margin = 10; + let arrow = this.popup.querySelector('.arrow'); + + let style = this.windowEl.style; + style.width = ''; + style.height = ''; + + let arrowStyle = arrow.style; + arrowStyle.top = ''; + arrowStyle.bottom = ''; + + let parentRect = this.parent.getBoundingClientRect(); + let popoverRect = this.windowEl.getBoundingClientRect(); + let arrowRect = arrow.getBoundingClientRect(); + let clamp = (value, min, max) => Math.min(Math.max(value, min), max); + + let arrowHeight = Math.floor(arrowRect.height / 2); + let arrowOffset = arrowHeight + margin / 2; + + let docEl = this.document.documentElement; + let maxRight = Math.min(window.innerWidth, docEl.clientWidth) - margin; + let maxBottom = Math.min(window.innerHeight, docEl.clientHeight) - margin; + let maxWith = maxRight - margin; + let maxHeight = maxBottom - margin - arrowHeight; + + let width = clamp(popoverRect.width, parentRect.width, maxWith); + let height = popoverRect.height; + + let left = parentRect.left + parentRect.width / 2 - width / 2; + left = clamp(left, margin, maxRight - width); + + let top = parentRect.top + parentRect.height + arrowOffset; + let showTop = top + height > maxBottom; + if (showTop) top = parentRect.top - height - arrowOffset; + top = Math.max(top, margin); + + if (showTop) + arrowStyle.bottom = `0`; + else + arrowStyle.top = `0`; + + let arrowLeft = (parentRect.left - left) + parentRect.width / 2; + arrowLeft = clamp(arrowLeft, arrowHeight, width - arrowHeight); + arrowStyle.left = `${arrowLeft}px`; + + style.top = `${top}px`; + style.left = `${left}px`; + style.width = `${width}px`; + if (height > maxHeight) style.height = `${maxHeight}px`; + } +} + +ngModule.vnComponent('vnPopover', { + controller: Popover +}); diff --git a/front/core/components/popover/popover.spec.js b/front/core/components/popover/index.spec.js similarity index 100% rename from front/core/components/popover/popover.spec.js rename to front/core/components/popover/index.spec.js diff --git a/front/core/components/popover/popover.html b/front/core/components/popover/popover.html deleted file mode 100644 index 7a29ba817..000000000 --- a/front/core/components/popover/popover.html +++ /dev/null @@ -1,6 +0,0 @@ -
-
-
-
-
-
\ No newline at end of file diff --git a/front/core/components/popover/popover.js b/front/core/components/popover/popover.js deleted file mode 100644 index 16969acbe..000000000 --- a/front/core/components/popover/popover.js +++ /dev/null @@ -1,201 +0,0 @@ -import ngModule from '../../module'; -import Component from '../../lib/component'; -import template from './popover.html'; -import './style.scss'; - -/** - * A simple popover. - * - * @property {HTMLElement} parent The parent element to show drop down relative to - * - * @event open Thrown when popover is displayed - * @event close Thrown when popover is hidden - */ -export default class Popover extends Component { - constructor($element, $scope, $timeout, $transitions, $transclude, $compile) { - super($element, $scope); - this.$timeout = $timeout; - this.$transitions = $transitions; - this._shown = false; - - this.element = $compile(template)($scope)[0]; - - this.popover = this.element.querySelector('.popover'); - this.popover.addEventListener('mousedown', e => this.onMouseDown(e)); - - this.arrow = this.element.querySelector('.arrow'); - this.content = this.element.querySelector('.content'); - - $transclude($scope.$parent, - clone => angular.element(this.content).append(clone)); - } - - $onDestroy() { - this.hide(); - } - - /** - * @type {HTMLElement} The popover child. - */ - get child() { - return this.content.firstChild; - } - - set child(value) { - this.content.innerHTML = ''; - this.content.appendChild(value); - } - - /** - * @type {Boolean} Wether to show or hide the popover. - */ - get shown() { - return this._shown; - } - - set shown(value) { - if (value) - this.show(); - else - this.hide(); - } - - /** - * Shows the popover emitting the open signal. If a parent is specified - * it is shown in a visible relative position to it. - * - * @param {HTMLElement} parent Overrides the parent property - */ - show(parent) { - if (this._shown) return; - - if (parent) this.parent = parent; - - this._shown = true; - - if (!this.showTimeout) { - this.document.body.appendChild(this.element); - this.element.style.display = 'block'; - } - - this.$timeout.cancel(this.showTimeout); - this.showTimeout = this.$timeout(() => { - this.showTimeout = null; - this.element.classList.add('shown'); - }, 30); - - this.docKeyDownHandler = e => this.onDocKeyDown(e); - this.document.addEventListener('keydown', this.docKeyDownHandler); - - this.bgMouseDownHandler = e => this.onBgMouseDown(e); - this.element.addEventListener('mousedown', this.bgMouseDownHandler); - - this.deregisterCallback = this.$transitions.onStart({}, () => this.hide()); - this.relocate(); - this.emit('open'); - } - - /** - * Hides the popover emitting the close signal. - */ - hide() { - if (!this._shown) return; - - this._shown = false; - this.element.classList.remove('shown'); - - this.$timeout.cancel(this.showTimeout); - this.showTimeout = this.$timeout(() => { - this.showTimeout = null; - this.element.style.display = 'none'; - this.document.body.removeChild(this.element); - this.emit('close'); - }, 250); - - this.document.removeEventListener('keydown', this.docKeyDownHandler); - this.docKeyDownHandler = null; - - this.element.removeEventListener('mousedown', this.bgMouseDownHandler); - this.bgMouseDownHandler = null; - - if (this.deregisterCallback) this.deregisterCallback(); - this.emit('closeStart'); - } - - /** - * Repositions the popover to a correct location relative to the parent. - */ - relocate() { - if (!(this.parent && this._shown)) return; - - let margin = 10; - - let style = this.popover.style; - style.width = ''; - style.height = ''; - - let arrowStyle = this.arrow.style; - arrowStyle.top = ''; - arrowStyle.bottom = ''; - - let parentRect = this.parent.getBoundingClientRect(); - let popoverRect = this.popover.getBoundingClientRect(); - let arrowRect = this.arrow.getBoundingClientRect(); - let clamp = (value, min, max) => Math.min(Math.max(value, min), max); - - let arrowHeight = Math.floor(arrowRect.height / 2); - let arrowOffset = arrowHeight + margin / 2; - - let docEl = this.document.documentElement; - let maxRight = Math.min(window.innerWidth, docEl.clientWidth) - margin; - let maxBottom = Math.min(window.innerHeight, docEl.clientHeight) - margin; - let maxWith = maxRight - margin; - let maxHeight = maxBottom - margin - arrowHeight; - - let width = clamp(popoverRect.width, parentRect.width, maxWith); - let height = popoverRect.height; - - let left = parentRect.left + parentRect.width / 2 - width / 2; - left = clamp(left, margin, maxRight - width); - - let top = parentRect.top + parentRect.height + arrowOffset; - let showTop = top + height > maxBottom; - if (showTop) top = parentRect.top - height - arrowOffset; - top = Math.max(top, margin); - - if (showTop) - arrowStyle.bottom = `0`; - else - arrowStyle.top = `0`; - - let arrowLeft = (parentRect.left - left) + parentRect.width / 2; - arrowLeft = clamp(arrowLeft, arrowHeight, width - arrowHeight); - arrowStyle.left = `${arrowLeft}px`; - - style.top = `${top}px`; - style.left = `${left}px`; - style.width = `${width}px`; - if (height > maxHeight) style.height = `${maxHeight}px`; - } - - onDocKeyDown(event) { - if (event.defaultPrevented) return; - if (event.code == 'Escape') - this.hide(); - } - - onMouseDown(event) { - this.lastMouseEvent = event; - } - - onBgMouseDown(event) { - if (event == this.lastMouseEvent || event.defaultPrevented) return; - this.hide(); - } -} -Popover.$inject = ['$element', '$scope', '$timeout', '$transitions', '$transclude', '$compile']; - -ngModule.component('vnPopover', { - controller: Popover, - transclude: true -}); diff --git a/front/core/components/popover/style.scss b/front/core/components/popover/style.scss index cc8199134..decfc4733 100644 --- a/front/core/components/popover/style.scss +++ b/front/core/components/popover/style.scss @@ -1,7 +1,6 @@ @import "variables"; .vn-popover { - display: none; z-index: 20; position: fixed; top: 0; @@ -20,7 +19,7 @@ transform: translateY(0); opacity: 1; } - & > .popover { + & > .window { position: absolute; box-shadow: 0 .1em .4em $color-shadow; z-index: 0; diff --git a/front/core/components/popup/index.js b/front/core/components/popup/index.js index 1d22adff1..dfafcd7d4 100644 --- a/front/core/components/popup/index.js +++ b/front/core/components/popup/index.js @@ -12,6 +12,7 @@ export default class Popup extends Component { this.$transclude = $transclude; this._shown = false; this.displayMode = 'centered'; + this.template = template; } $onDestroy() { @@ -39,11 +40,12 @@ export default class Popup extends Component { if (this.shown) return; this._shown = true; - let linkFn = this.$compile(template); + let linkFn = this.$compile(this.template); this.$contentScope = this.$.$new(); this.popup = linkFn(this.$contentScope, null, {parentBoundTranscludeFn: this.$transclude} )[0]; + this.windowEl = this.popup.querySelector('.window'); let classList = this.popup.classList; classList.add(this.displayMode); @@ -84,22 +86,26 @@ export default class Popup extends Component { this.popup.classList.remove('shown'); this.$timeout.cancel(this.transitionTimeout); - this.transitionTimeout = this.$timeout(() => { - this.transitionTimeout = null; - this.document.body.removeChild(this.popup); - - this.$contentScope.$destroy(); - this.popup.remove(); - this.popup = null; - - this.emit('close'); - }, 200); + this.transitionTimeout = this.$timeout( + () => this.onClose(), 200); this.lastEvent = null; this._shown = false; this.emit('closeStart'); } + onClose() { + this.transitionTimeout = null; + this.document.body.removeChild(this.popup); + + this.$contentScope.$destroy(); + this.popup.remove(); + this.popup = null; + this.windowEl = null; + + this.emit('close'); + } + onWindowMouseDown(event) { this.lastEvent = event; } diff --git a/front/core/components/popup/style.scss b/front/core/components/popup/style.scss index 9611e13e7..42d69141d 100644 --- a/front/core/components/popup/style.scss +++ b/front/core/components/popup/style.scss @@ -30,7 +30,7 @@ overflow: auto; box-sizing: border-box; max-height: 100%; - transform: scale3d(.5, .5, .5); + transform: scale3d(.9, .9, .9); transition: transform 200ms ease-in-out; } &.shown > .window { diff --git a/front/core/components/radio/style.scss b/front/core/components/radio/style.scss index dd1555b7f..787c0986e 100644 --- a/front/core/components/radio/style.scss +++ b/front/core/components/radio/style.scss @@ -1,6 +1,6 @@ @import "variables"; -vn-radio { +.vn-radio { & > .btn { border-radius: 50%; @@ -22,4 +22,7 @@ vn-radio { background-color: $color-main; } } + &.disabled.checked > .btn > .mark { + background-color: $color-font-secondary; + } } diff --git a/front/core/components/range/style.scss b/front/core/components/range/style.scss index 878035f3a..a370b4c39 100644 --- a/front/core/components/range/style.scss +++ b/front/core/components/range/style.scss @@ -35,7 +35,7 @@ } } -vn-range { +.vn-range { & > label { font-size: 12px; diff --git a/front/core/components/searchbar/search-panel.js b/front/core/components/searchbar/search-panel.js index 96dc67ed5..f473c2b04 100644 --- a/front/core/components/searchbar/search-panel.js +++ b/front/core/components/searchbar/search-panel.js @@ -1,6 +1,6 @@ import Component from '../../lib/component'; -export default class extends Component { +export default class SearchPanel extends Component { set filter(value) { this.$.filter = value; } @@ -13,6 +13,6 @@ export default class extends Component { if (!this.onSubmit) throw new Error('SearchPanel::onSubmit() method not defined'); - this.onSubmit(this.filter); + this.onSubmit({$filter: this.filter}); } } diff --git a/front/core/components/searchbar/searchbar.js b/front/core/components/searchbar/searchbar.js index f3db40a93..d74a4e7a6 100644 --- a/front/core/components/searchbar/searchbar.js +++ b/front/core/components/searchbar/searchbar.js @@ -65,23 +65,24 @@ export default class Controller extends Component { openPanel(event) { if (event.defaultPrevented) return; + this.$.popover.show(this.element); this.$panelScope = this.$.$new(); - this.$panel = this.$compile(`<${this.panel}/>`)(this.$panelScope); - let panel = this.$panel[0].$ctrl; + this.panelEl = this.$compile(`<${this.panel}/>`)(this.$panelScope)[0]; + let panel = this.panelEl.$ctrl; if (this.shownFilter) panel.filter = JSON.parse(JSON.stringify(this.shownFilter)); - panel.onSubmit = filter => this.onPanelSubmit(filter); + panel.onSubmit = filter => this.onPanelSubmit(filter.$filter); - this.$.popover.parent = this.element; - this.$.popover.child = this.$panel[0]; - this.$.popover.show(); + this.$.popover.content.appendChild(this.panelEl); } onPopoverClose() { this.$panelScope.$destroy(); - this.$panel.remove(); - this.$panel = null; + this.$panelScope = null; + + this.panelEl.remove(); + this.panelEl = null; } onPanelSubmit(filter) { diff --git a/front/core/components/searchbar/searchbar.spec.js b/front/core/components/searchbar/searchbar.spec.js index 92883c47b..4cd7ec74a 100644 --- a/front/core/components/searchbar/searchbar.spec.js +++ b/front/core/components/searchbar/searchbar.spec.js @@ -8,11 +8,11 @@ describe('Component vnSearchbar', () => { beforeEach(ngModule('vnCore')); - beforeEach(angular.mock.inject(($componentController, _$state_, $rootScope, $compile) => { + beforeEach(angular.mock.inject(($componentController, _$state_, $rootScope) => { $scope = $rootScope.$new(); $state = _$state_; $element = angular.element(``); - controller = $componentController('vnSearchbar', {$element, $state, $scope, $compile}); + controller = $componentController('vnSearchbar', {$element, $scope}); controller.panel = 'vn-client-search-panel'; })); @@ -39,7 +39,7 @@ describe('Component vnSearchbar', () => { describe('onStateChange()', () => { it(`should set a formated _filter in the controller`, () => { spyOn(controller, 'doSearch'); - Object.assign(controller.$state.params, {q: '{"id": 999}'}); + Object.assign($state.params, {q: '{"id": 999}'}); controller.onStateChange(); @@ -71,27 +71,11 @@ describe('Component vnSearchbar', () => { describe('filter() setter', () => { it(`should call $state.go() to replace the current state location instead of creating a new one`, () => { controller._filter = {}; - spyOn(controller.$state, 'go'); + spyOn($state, 'go'); controller.filter = {expected: 'filter'}; expect(controller._filter).toEqual(controller.filter); - expect(controller.$state.go).toHaveBeenCalledWith('.', Object({q: '{"expected":"filter"}'}), Object({location: 'replace'})); - }); - }); - - describe('onPopoverClose()', () => { - it(`should get rid of $panel and $panelScope`, () => { - controller.$panel = { - I: 'should disappear', - remove: () => {} - }; - - controller.$panelScope = {$destroy: jasmine.createSpy('$destroy')}; - - controller.onPopoverClose(); - - expect(controller.$panelScope.$destroy).toHaveBeenCalledWith(); - expect(controller.$panel).toBeNull(); + expect($state.go).toHaveBeenCalledWith('.', Object({q: '{"expected":"filter"}'}), Object({location: 'replace'})); }); }); diff --git a/front/core/components/table/style.scss b/front/core/components/table/style.scss index 839e1a7bb..a3fd4513b 100644 --- a/front/core/components/table/style.scss +++ b/front/core/components/table/style.scss @@ -169,11 +169,11 @@ vn-table { } } } - vn-textfield { + .vn-textfield { float: right; margin: 0!important; } - vn-check { + .vn-check { margin: 0; } } \ No newline at end of file diff --git a/front/core/components/toggle/index.js b/front/core/components/toggle/index.js index 70698ede8..bc3851bbc 100644 --- a/front/core/components/toggle/index.js +++ b/front/core/components/toggle/index.js @@ -11,13 +11,12 @@ export default class Toggle extends FormInput { constructor($element, $) { super($element, $); this.initTabIndex(); - this.classList.add('vn-toggle'); this.element.addEventListener('click', e => this.onClick(e)); this.element.addEventListener('keydown', e => this.onKeydown(e)); } onKeydown(event) { - if (!event.defaultPrevented && event.code == 'Space') + if (!event.defaultPrevented && event.key == ' ') this.element.click(); } @@ -26,10 +25,9 @@ export default class Toggle extends FormInput { return true; } - changed() { + change(value) { this.$.$applyAsync(); - this.element.dispatchEvent(new Event('change')); - this.emit('change', {value: this.field}); + super.change(value); } } diff --git a/front/core/components/toggle/style.scss b/front/core/components/toggle/style.scss index a373b6f4c..af3dc3ae5 100644 --- a/front/core/components/toggle/style.scss +++ b/front/core/components/toggle/style.scss @@ -7,11 +7,8 @@ align-items: center; outline: none; - &.disabled { - cursor: inherit; - } & > span { - font-size: $font-size; + font-size: 1rem; text-overflow: ellipsis; white-space: nowrap; overflow: hidden; @@ -28,13 +25,6 @@ margin-right: .6em; border: 2px solid #666; } - &.checked > .btn { - border-color: $color-main; - - & > .focus-mark { - background-color: rgba($color-main, .15); - } - } & > .btn > .focus-mark { position: absolute; top: 50%; @@ -49,6 +39,23 @@ transition: transform 250ms; background-color: rgba(0, 0, 0, .1); } + &.checked > .btn { + border-color: $color-main; + + & > .focus-mark { + background-color: rgba($color-main, .15); + } + } + &.disabled { + cursor: inherit; + + &.checked > .btn { + border-color: $color-font-secondary; + } + } + &.readonly { + cursor: inherit; + } &:focus:not(.disabled) > .btn > .focus-mark { transform: scale3d(1, 1, 1); } diff --git a/front/core/components/wday-picker/style.scss b/front/core/components/wday-picker/style.scss index c50b20718..c6899ad6a 100644 --- a/front/core/components/wday-picker/style.scss +++ b/front/core/components/wday-picker/style.scss @@ -1,6 +1,6 @@ @import "effects"; -vn-wday-picker { +.vn-wday-picker { text-align: center; &:focus { diff --git a/front/core/directives/focus.js b/front/core/directives/focus.js index b9527479b..28535430a 100644 --- a/front/core/directives/focus.js +++ b/front/core/directives/focus.js @@ -1,7 +1,5 @@ import ngModule from '../module'; - -const regex = /Android|webOS|iPhone|iPad|iPod|BlackBerry|Windows Phone/i; -export const isMobile = regex.test(navigator.userAgent); +import isMobile from '../lib/is-mobile'; export function focus($scope, input) { if (isMobile) return; diff --git a/front/core/directives/popover.js b/front/core/directives/popover.js index ad147e9c0..5d86665ba 100644 --- a/front/core/directives/popover.js +++ b/front/core/directives/popover.js @@ -1,5 +1,5 @@ import ngModule from '../module'; -import Popover from '../components/popover/popover'; +import Popover from '../components/popover'; import {kebabToCamel} from '../lib/string'; /** @@ -15,10 +15,8 @@ export function directive() { if (event.defaultPrevented) return; let popoverKey = kebabToCamel($attrs.vnPopover); let popover = $scope[popoverKey]; - if (popover instanceof Popover) { - popover.parent = $element[0]; - popover.show(); - } + if (popover instanceof Popover) + popover.show($element[0]); }); } }; diff --git a/front/core/directives/specs/dialog.spec.js b/front/core/directives/specs/dialog.spec.js index 670b28128..4d5a02e31 100644 --- a/front/core/directives/specs/dialog.spec.js +++ b/front/core/directives/specs/dialog.spec.js @@ -17,9 +17,9 @@ describe('Directive dialog', () => { }); }; - beforeEach(angular.mock.inject($componentController => { - $element = angular.element('
'); - controller = $componentController('vnDialog', {$element: $element, $transclude: null}); + beforeEach(angular.mock.inject(($rootScope, $compile) => { + $element = $compile('')($rootScope); + controller = $element.controller('vnDialog'); })); it('should call show() function if dialog is a instance of vnDialog', () => { diff --git a/front/core/directives/zoom-image.js b/front/core/directives/zoom-image.js index 574a6e549..607dbe337 100644 --- a/front/core/directives/zoom-image.js +++ b/front/core/directives/zoom-image.js @@ -25,7 +25,7 @@ export function directive($timeout) { } function onKeyDown(event) { - if (event.keyCode === 27) + if (event.key === 'Escape') destroyContainers(); } diff --git a/front/core/lib/component.js b/front/core/lib/component.js index 173a46e9f..979420b22 100644 --- a/front/core/lib/component.js +++ b/front/core/lib/component.js @@ -39,6 +39,7 @@ export default class Component extends EventEmitter { get window() { return this.document.defaultView; } + /** * The component owner document. */ @@ -57,21 +58,16 @@ export default class Component extends EventEmitter { return this.$translate.instant(string, params); } - createBoundTranscludeFn(transcludeFn) { + createBoundTranscludeFn(linkFn) { let scope = this.$; let previousBoundTranscludeFn = this.$transclude.$$boundTransclude; - function vnBoundTranscludeFn( - transcludedScope, - cloneFn, - controllers, - futureParentElement, - containingScope) { + function vnBoundTranscludeFn(transcludedScope, cloneFn, controllers, futureParentElement, containingScope) { if (!transcludedScope) { transcludedScope = scope.$new(false, containingScope); transcludedScope.$$transcluded = true; } - return transcludeFn(transcludedScope, cloneFn, { + return linkFn(transcludedScope, cloneFn, { parentBoundTranscludeFn: previousBoundTranscludeFn, transcludeControllers: controllers, futureParentElement: futureParentElement @@ -81,10 +77,37 @@ export default class Component extends EventEmitter { return vnBoundTranscludeFn; } + + fillDefaultSlot(template) { + let linkFn = this.$compile(template); + this.$transclude.$$boundTransclude = this.createBoundTranscludeFn(linkFn); + } + + fillSlot(slot, template) { + let slots = this.$transclude.$$boundTransclude.$$slots; + let linkFn = this.$compile(template); + slots[slot] = this.createBoundTranscludeFn(linkFn); + } + + copySlot(slot, $transclude) { + this.$transclude.$$boundTransclude.$$slots[slot] = + $transclude.$$boundTransclude.$$slots[slot]; + } } Component.$inject = ['$element', '$scope']; -function runFn($translate, $q, $http, $state, $stateParams, $timeout, $transitions, $compile, vnApp) { +function runFn( + $translate, + $q, + $http, + $state, + $stateParams, + $timeout, + $transitions, + $compile, + $filter, + $interpolate, + vnApp) { Object.assign(Component.prototype, { $translate, $q, @@ -94,6 +117,8 @@ function runFn($translate, $q, $http, $state, $stateParams, $timeout, $transitio $timeout, $transitions, $compile, + $filter, + $interpolate, vnApp }); } @@ -106,6 +131,8 @@ runFn.$inject = [ '$timeout', '$transitions', '$compile', + '$filter', + '$interpolate', 'vnApp' ]; diff --git a/front/core/lib/event-emitter.js b/front/core/lib/event-emitter.js index 022e4e98c..83e361253 100644 --- a/front/core/lib/event-emitter.js +++ b/front/core/lib/event-emitter.js @@ -51,17 +51,17 @@ export default class EventEmitter { * Emits an event. * * @param {String} eventName The event name - * @param {...*} args Arguments to pass to the callbacks + * @param {Object} args Arguments to pass to the callbacks */ - emit(eventName) { + emit(eventName, args) { if (!this.$events || !this.$events[eventName]) return; - let args = Array.prototype.slice.call(arguments, 1); + args = Object.assign({$this: this}, args); let callbacks = this.$events[eventName]; for (let callback of callbacks) - callback.callback.apply(callback.thisArg, args); + callback.callback.call(callback.thisArg, args); } /** diff --git a/front/core/lib/is-mobile.js b/front/core/lib/is-mobile.js new file mode 100644 index 000000000..5fae749df --- /dev/null +++ b/front/core/lib/is-mobile.js @@ -0,0 +1,4 @@ + +const regex = /Android|webOS|iPhone|iPad|iPod|BlackBerry|Windows Phone/i; +const isMobile = regex.test(navigator.userAgent); +export default isMobile; diff --git a/front/core/locale/es.yml b/front/core/locale/es.yml index 1fcd12b98..1e1e4da4c 100644 --- a/front/core/locale/es.yml +++ b/front/core/locale/es.yml @@ -11,7 +11,6 @@ Hide: Ocultar Next: Siguiente Finalize: Finalizar Previous: Anterior -Load more: Cargar más Auto-scroll interrupted, please adjust the search: Auto-scroll interrumpido, por favor ajusta la búsqueda Value can't be empty: El valor no puede estar vacío Value should be empty: El valor debe estar vacío @@ -60,3 +59,7 @@ No records found: No se han encontrado elementos Day: Día Days: Días Go up: Ir arriba +Loading...: Cargando... +No results found: Sin resultados +No data: Sin datos +Load more: Cargar más \ No newline at end of file diff --git a/front/salix/components/login/style.scss b/front/salix/components/login/style.scss index ea894d62e..e098fbdb4 100644 --- a/front/salix/components/login/style.scss +++ b/front/salix/components/login/style.scss @@ -30,10 +30,10 @@ vn-login { padding-bottom: 1em; } & > form { - & > vn-textfield { + & > .vn-textfield { width: 100%; } - & > vn-check { + & > .vn-check { display: block; .md-label { white-space: inherit; diff --git a/front/salix/locale/es.yml b/front/salix/locale/es.yml index 898728363..a7f1dc93a 100644 --- a/front/salix/locale/es.yml +++ b/front/salix/locale/es.yml @@ -52,3 +52,4 @@ List: Listado # Misc Phone: Teléfono +Id: Id diff --git a/front/salix/styles/misc.scss b/front/salix/styles/misc.scss index 82f4615c9..0ae30becd 100644 --- a/front/salix/styles/misc.scss +++ b/front/salix/styles/misc.scss @@ -3,22 +3,22 @@ form vn-horizontal { align-items: center; + min-height: 2.8em; & > * { box-sizing: border-box; - min-height: 2.8em; - padding: 0 $spacing-sm; + margin: 0 $spacing-xs; &:first-child { - padding-left: 0; - padding-right: $spacing-xs; + margin-left: 0; + margin-right: $spacing-sm; } &:last-child { - padding-left: $spacing-xs; - padding-right: 0; + margin-left: $spacing-sm; + margin-right: 0; } &:first-child:last-child { - padding: 0; + margin: 0; } } @@ -30,7 +30,7 @@ form vn-horizontal { &, &:first-child, &:last-child { - padding: 0; + margin: 0; } } } diff --git a/front/salix/styles/modal-form.scss b/front/salix/styles/modal-form.scss index e0318c9d2..0f728178d 100644 --- a/front/salix/styles/modal-form.scss +++ b/front/salix/styles/modal-form.scss @@ -16,7 +16,7 @@ vn-dialog.modal-form { & > div { padding: 0 !important; } - vn-textfield { + .vn-textfield { width: 100%; } .buttons { diff --git a/modules/agency/front/calendar/style.scss b/modules/agency/front/calendar/style.scss index f48c7d6b6..3fe23278e 100644 --- a/modules/agency/front/calendar/style.scss +++ b/modules/agency/front/calendar/style.scss @@ -23,7 +23,7 @@ vn-zone-calendar { flex-wrap: wrap; justify-content: space-evenly; - & > vn-calendar { + & > .vn-calendar { max-width: 18em; .day { diff --git a/modules/agency/front/location/style.scss b/modules/agency/front/location/style.scss index d1597e460..d03701e42 100644 --- a/modules/agency/front/location/style.scss +++ b/modules/agency/front/location/style.scss @@ -1,14 +1,14 @@ @import "variables"; vn-treeview-child { - .content > vn-check:not(.indeterminate) { + .content > .vn-check:not(.indeterminate) { color: $color-main; & > .btn { border-color: $color-main; } } - .content > vn-check.checked { + .content > .vn-check.checked { color: $color-main; } } \ No newline at end of file diff --git a/modules/claim/front/action/style.scss b/modules/claim/front/action/style.scss index 0124b716b..aef8d2cfd 100644 --- a/modules/claim/front/action/style.scss +++ b/modules/claim/front/action/style.scss @@ -9,7 +9,7 @@ vn-claim-action { flex: 1 } - vn-check { + .vn-check { flex: none; } } diff --git a/modules/claim/front/detail/style.scss b/modules/claim/front/detail/style.scss index e555cb305..2b5727d48 100644 --- a/modules/claim/front/detail/style.scss +++ b/modules/claim/front/detail/style.scss @@ -1,7 +1,7 @@ @import "variables"; vn-claim-detail { - vn-textfield { + .vn-textfield { margin: 0!important; max-width: 100px; } diff --git a/modules/client/front/dms/create/style.scss b/modules/client/front/dms/create/style.scss index b47544b12..73f136fc1 100644 --- a/modules/client/front/dms/create/style.scss +++ b/modules/client/front/dms/create/style.scss @@ -1,5 +1,5 @@ vn-ticket-request { - vn-textfield { + .vn-textfield { margin: 0!important; max-width: 100px; } diff --git a/modules/client/front/dms/edit/style.scss b/modules/client/front/dms/edit/style.scss index b47544b12..73f136fc1 100644 --- a/modules/client/front/dms/edit/style.scss +++ b/modules/client/front/dms/edit/style.scss @@ -1,5 +1,5 @@ vn-ticket-request { - vn-textfield { + .vn-textfield { margin: 0!important; max-width: 100px; } diff --git a/modules/item/back/models/item.json b/modules/item/back/models/item.json index 78396793b..7e2a93e11 100644 --- a/modules/item/back/models/item.json +++ b/modules/item/back/models/item.json @@ -14,53 +14,68 @@ "id": { "type": "Number", "id": true, - "description": "Identifier" + "description": "Id" }, "name": { - "type": "String" + "type": "String", + "description": "Name" }, "size": { - "type": "Number" + "type": "Number", + "description": "Size" }, "category": { - "type": "String" + "type": "String", + "description": "Category" }, "typeFk": { "type": "Number", + "description": "Type", "required": true }, "stems": { - "type": "Number" + "type": "Number", + "description": "Stems" }, "description": { - "type": "String" + "type": "String", + "description": "Description" }, "isOnOffer": { - "type": "Boolean" + "type": "Boolean", + "description": "Offer" }, "isBargain": { - "type": "Boolean" + "type": "Boolean", + "description": "Bargain" }, "isActive": { - "type": "Boolean" + "type": "Boolean", + "description": "Active" }, "comment": { - "type": "String" + "type": "String", + "description": "Comment" }, "relevancy": { - "type": "Number" + "type": "Number", + "description": "Relevancy" }, "density": { - "type": "Number" + "type": "Number", + "description": "Density" }, "image": { - "type": "String" + "type": "String", + "description": "Image" }, "longName": { - "type": "String" + "type": "String", + "description": "Long name" }, "subName": { - "type": "String" + "type": "String", + "description": "Subname" }, "tag5": { "type": "String" @@ -99,7 +114,8 @@ "type": "String" }, "hasKgPrice": { - "type": "Boolean" + "type": "Boolean", + "description": "Price per Kg" } }, "relations": { diff --git a/modules/item/front/descriptor/style.scss b/modules/item/front/descriptor/style.scss index 257e46e1c..c4847bead 100644 --- a/modules/item/front/descriptor/style.scss +++ b/modules/item/front/descriptor/style.scss @@ -8,7 +8,7 @@ vn-item-descriptor { display: block; } vn-dialog[vn-id=regularize]{ - vn-textfield{ + .vn-textfield{ width: 100% } } diff --git a/modules/item/front/search-panel/index.html b/modules/item/front/search-panel/index.html index e8209df83..ea0d854f5 100644 --- a/modules/item/front/search-panel/index.html +++ b/modules/item/front/search-panel/index.html @@ -22,8 +22,9 @@ @@ -42,13 +43,17 @@ label="Buyer"> - - - + + + Tags + + + - + + + More fields + + ng-click="$ctrl.fieldFilters.push({})"> - - - More fields - - - + + ng-model="fieldFilter.name" + data="$ctrl.moreFields" + value-field="name" + show-field="label" + show-filter="false" + translate-fields="['label']" + selection="info" + on-change="fieldFilter.value = null"> - - + +
+ + +
+
+ + +
+
+ + +
+
+ + +
+
- - - - diff --git a/modules/item/front/search-panel/index.js b/modules/item/front/search-panel/index.js index 098ec8042..6b3e7786d 100644 --- a/modules/item/front/search-panel/index.js +++ b/modules/item/front/search-panel/index.js @@ -2,19 +2,37 @@ import ngModule from '../module'; import SearchPanel from 'core/components/searchbar/search-panel'; class Controller extends SearchPanel { - constructor($scope, $element) { - super($scope, $element); - this.$ = $scope; - this.moreFields = [ - {field: 'id'}, - {field: 'description'}, - {field: 'name'} - ]; + constructor($element, $) { + super($element, $); + let model = 'Item'; + let moreFields = ['id', 'description', 'name', 'isActive']; + + let properties; + let validations = window.validations; + + if (validations && validations[model]) + properties = validations[model].properties; + else + properties = {}; + + this.moreFields = []; + for (let field of moreFields) { + let prop = properties[field]; + this.moreFields.push({ + name: field, + label: prop ? prop.description : field, + type: prop ? prop.type : null + }); + } } - initializeMoreFields() { - if (!this.$.filter.moreFields || !this.$.filter.moreFields.length) - this.$.filter.moreFields = [{}]; + get filter() { + let filter = this.$.filter; + + for (let fieldFilter of this.fieldFilters) + filter[fieldFilter.name] = fieldFilter.value; + + return filter; } set filter(value) { @@ -23,28 +41,20 @@ class Controller extends SearchPanel { if (!value.tags) value.tags = [{}]; + this.fieldFilters = []; + for (let field of this.moreFields) { + if (value[field.name] != undefined) { + this.fieldFilters.push({ + name: field.name, + value: value[field.name], + info: field + }); + } + } + this.$.filter = value; } - get itemTypes() { - if (this.$.filter) { - if (!this.$.filter.categoryFk) - return 'ItemTypes'; - return `ItemCategories/${this.$.filter.categoryFk}/itemTypes`; - } - } - - get filter() { - if (this.$.filter.moreFields) { - this.$.filter.moreFields.forEach(element => { - this.$.filter[element.field] = element.value; - }); - } - let filter = Object.assign({}, this.$.filter); - delete filter.moreFields; - return filter; - } - getSourceTable(selection) { if (!selection || selection.isFree === true) return null; @@ -56,6 +66,11 @@ class Controller extends SearchPanel { } else if (selection.sourceTable == null) return `ItemTags/filterItemTags/${selection.id}`; } + + removeField(index, field) { + this.fieldFilters.splice(index, 1); + this.$.filter[field] = undefined; + } } ngModule.component('vnItemSearchPanel', { diff --git a/modules/item/front/search-panel/locale/es.yml b/modules/item/front/search-panel/locale/es.yml index 660991827..197da0695 100644 --- a/modules/item/front/search-panel/locale/es.yml +++ b/modules/item/front/search-panel/locale/es.yml @@ -3,6 +3,6 @@ Origin: Origen Producer: Productor. With visible: Con visible Field: Campo -More fields: Mas campos +More fields: Más campos Add field: Añadir campo Remove field: Quitar campo \ No newline at end of file diff --git a/modules/order/front/catalog-search-panel/index.js b/modules/order/front/catalog-search-panel/index.js index 6ad88c978..7d5f1bfd1 100644 --- a/modules/order/front/catalog-search-panel/index.js +++ b/modules/order/front/catalog-search-panel/index.js @@ -3,5 +3,8 @@ import SearchPanel from 'core/components/searchbar/search-panel'; ngModule.component('vnOrderCatalogSearchPanel', { template: require('./index.html'), - controller: SearchPanel + controller: SearchPanel, + bindings: { + onSubmit: '&?' + } }); diff --git a/modules/order/front/catalog/index.html b/modules/order/front/catalog/index.html index aee1b1ec6..37ef1fd90 100644 --- a/modules/order/front/catalog/index.html +++ b/modules/order/front/catalog/index.html @@ -1,111 +1,69 @@ -
- - - -
- More than {{model.limit}} results -
-
- - - - - - -
-
- - - - - - Enter a new search - - - No results - - + -
- -
- +
+ +
+ +
+
+

+ {{::item.name}} +

+

+ {{::item.subName}} +

+
+ + + + + +
-
-

- {{::item.name}} -

-

- {{::item.subName}} -

-
- - - - - - +
+
+
+
- -
+ diff --git a/modules/order/front/catalog/index.js b/modules/order/front/catalog/index.js index 758c56f0e..adb66171e 100644 --- a/modules/order/front/catalog/index.js +++ b/modules/order/front/catalog/index.js @@ -8,20 +8,19 @@ class Controller { this.$stateParams = $state.params; // Static autocomplete data - this.wayList = [ + this.orderWays = [ {way: 'ASC', name: 'Ascendant'}, {way: 'DESC', name: 'Descendant'}, ]; - this.defaultFieldList = [ - {field: 'relevancy DESC, name', name: 'Default'}, + this.defaultOrderFields = [ + {field: 'relevancy DESC, name', name: 'Relevancy'}, {field: 'showOrder, price', name: 'Color'}, {field: 'name', name: 'Name'}, {field: 'price', name: 'Price'} ]; - this.fieldList = []; - this.fieldList = this.fieldList.concat(this.defaultFieldList); - this._way = this.wayList[0].way; - this._field = this.fieldList[0].field; + this.orderFields = [].concat(this.defaultOrderFields); + this._orderWay = this.orderWays[0].way; + this._orderField = this.orderFields[0].field; } /** @@ -51,43 +50,41 @@ class Controller { }); // Add default filters - Replaces tags with same name - this.defaultFieldList.forEach(defaultField => { + this.defaultOrderFields.forEach(orderField => { const index = newFilterList.findIndex(newfield => { - return newfield.name == defaultField.name; + return newfield.name == orderField.name; }); if (index > -1) - newFilterList[index] = defaultField; + newFilterList[index] = orderField; else - newFilterList.push(defaultField); + newFilterList.push(orderField); }); - this.fieldList = newFilterList; + this.orderFields = newFilterList; } /** * Get order way ASC/DESC */ - get way() { - return this._way; + get orderWay() { + return this._orderWay; } - set way(value) { - this._way = value; - + set orderWay(value) { + this._orderWay = value; if (value) this.applyOrder(); } /** * Get order fields */ - get field() { - return this._field; + get orderField() { + return this._orderField; } - set field(value) { - this._field = value; - + set orderField(value) { + this._orderField = value; if (value) this.applyOrder(); } @@ -97,16 +94,11 @@ class Controller { * @return {Object} - Order param */ getOrderBy() { - let field = this.$scope.field; - let args = { - field: this.field, - way: this.way + return { + field: this.orderField, + way: this.orderWay, + isTag: !!(this.orderSelection && this.orderSelection.isTag) }; - - if (field.selection && field.selection.isTag) - args.isTag = true; - - return args; } /** @@ -129,10 +121,6 @@ class Controller { if (this.order && this.order.isConfirmed) this.$state.go('order.card.line'); } - - get isRefreshing() { - return this.$scope.model && this.$scope.model.status == 'loading'; - } } Controller.$inject = ['$scope', '$state']; diff --git a/modules/order/front/catalog/index.spec.js b/modules/order/front/catalog/index.spec.js index 98494b3ca..b6e70bb4a 100644 --- a/modules/order/front/catalog/index.spec.js +++ b/modules/order/front/catalog/index.spec.js @@ -25,17 +25,21 @@ describe('Order', () => { let unexpectedResult = [{tagFk: 5, name: 'Color'}]; controller.onDataChange(); - expect(controller.fieldList.length).toEqual(5); - expect(controller.fieldList).toEqual(jasmine.arrayContaining(expectedResult)); - expect(controller.fieldList).not.toEqual(jasmine.arrayContaining(unexpectedResult)); + expect(controller.orderFields.length).toEqual(5); + expect(controller.orderFields).toEqual(jasmine.arrayContaining(expectedResult)); + expect(controller.orderFields).not.toEqual(jasmine.arrayContaining(unexpectedResult)); }); }); describe('getOrderBy()', () => { it(`should return an object with order params`, () => { - controller.field = 'relevancy DESC, name'; - controller.way = 'DESC'; - let expectedResult = {field: 'relevancy DESC, name', way: 'DESC'}; + controller.orderField = 'relevancy DESC, name'; + controller.orderWay = 'DESC'; + let expectedResult = { + field: 'relevancy DESC, name', + way: 'DESC', + isTag: false + }; let result = controller.getOrderBy(); expect(result).toEqual(expectedResult); diff --git a/modules/order/front/descriptor/index.js b/modules/order/front/descriptor/index.js index bf197e070..96cee0bbd 100644 --- a/modules/order/front/descriptor/index.js +++ b/modules/order/front/descriptor/index.js @@ -1,5 +1,4 @@ import ngModule from '../module'; -import './style.scss'; class Controller { constructor($translate, $scope, vnApp, $http, $state) { diff --git a/modules/order/front/descriptor/style.scss b/modules/order/front/descriptor/style.scss deleted file mode 100644 index 469020e50..000000000 --- a/modules/order/front/descriptor/style.scss +++ /dev/null @@ -1,5 +0,0 @@ -vn-label-value[label=Total]{ - padding-top: 10px; - display: block; - font-size: 1.2em; -} \ No newline at end of file diff --git a/modules/order/front/filter/index.html b/modules/order/front/filter/index.html index 3f2d2094b..68691e0a7 100644 --- a/modules/order/front/filter/index.html +++ b/modules/order/front/filter/index.html @@ -7,19 +7,20 @@
- - + + - - + - search + - - - keyboard_arrow_down - - - - + + + + + + +
+ More than {{model.limit}} results +
+
+ @@ -58,21 +77,24 @@ label="Search tag" ng-model="$ctrl.value"> - search + - - keyboard_arrow_down - + + - + +
{ + this.$.$applyAsync(() => { let category; let type; @@ -111,7 +111,7 @@ class Controller { this.tags.push({ value: this.value, }); - this.$scope.search.value = null; + this.$.search.value = null; this.applyFilters(); } @@ -149,29 +149,16 @@ class Controller { if (event.defaultPrevented) return; event.preventDefault(); - this.$panelScope = this.$scope.$new(); - this.$panel = this.$compile(``)(this.$panelScope); - const panel = this.$panel[0].$ctrl; - panel.filter = this.filter; - panel.onSubmit = filter => this.onPanelSubmit(filter); - - this.$scope.popover.parent = this.$scope.search.element; - this.$scope.popover.child = this.$panel[0]; - this.$scope.popover.show(); + this.panelFilter = {}; + this.$.popover.show(this.$.search.element); } onPanelSubmit(filter) { - this.$scope.popover.hide(); + this.$.popover.hide(); this.tags.push(filter); this.applyFilters(); } - onPopoverClose() { - this.$panelScope.$destroy(); - this.$panel.remove(); - this.$panel = null; - } - /** * Updates url state params from filter values */ diff --git a/modules/order/front/filter/index.spec.js b/modules/order/front/filter/index.spec.js index 0b3be5a6c..8fb4baeca 100644 --- a/modules/order/front/filter/index.spec.js +++ b/modules/order/front/filter/index.spec.js @@ -31,13 +31,10 @@ describe('Order', () => { describe('order() setter', () => { it(`should call scope $applyAsync() method and apply filters from state params`, () => { $httpBackend.expect('GET', `Orders/4/getItemTypeAvailable?itemCategoryId=1`).respond(); - spyOn(controller.$scope, '$applyAsync').and.callThrough(); controller.order = {id: 4}; - expect(controller.$scope.$applyAsync).toHaveBeenCalledWith(jasmine.any(Function)); $scope.$apply(); - expect(controller.category).toEqual({id: 1, value: 'My Category'}); expect(controller.type).toEqual({id: 1, value: 'My type'}); }); diff --git a/modules/order/front/line/index.html b/modules/order/front/line/index.html index cdff9b35c..9204f3215 100644 --- a/modules/order/front/line/index.html +++ b/modules/order/front/line/index.html @@ -2,77 +2,83 @@ vn-id="watcher" data="$ctrl.rows"> - - - - - -

Subtotal {{$ctrl.subtotal | currency: 'EUR':2}}

-

VAT {{$ctrl.VAT | currency: 'EUR':2}}

-

Total {{$ctrl.order.total | currency: 'EUR':2}}

-
-
- - - - - Id - Description - Warehouse - Shipped - Quantity - Price - - - - - - - - - - - {{::row.itemFk | zeroFill:6}} - - - - - - - {{::row.warehouse.name}} - {{::row.shipped | date: 'dd/MM/yyyy'}} - {{::row.quantity}} - - {{::row.price | currency: 'EUR':2}} - - - - - - - - -
+ + +
+ Subtotal + {{$ctrl.subtotal | currency: 'EUR':2}} +
+
+ VAT + {{$ctrl.VAT | currency: 'EUR':2}} +
+
+ Total + {{$ctrl.order.total | currency: 'EUR':2}} +
- - - - -
+ + + + + + Id + Description + Warehouse + Shipped + Quantity + Price + + + + + + + + + + + {{::row.itemFk | zeroFill:6}} + + + + + + + {{::row.warehouse.name}} + {{::row.shipped | date: 'dd/MM/yyyy'}} + {{::row.quantity}} + + {{::row.price | currency: 'EUR':2}} + + + + + + + + + + + + diff --git a/modules/order/front/line/style.scss b/modules/order/front/line/style.scss index ceef14fa1..4da941a2c 100644 --- a/modules/order/front/line/style.scss +++ b/modules/order/front/line/style.scss @@ -8,20 +8,11 @@ vn-order-line { height: 50px; } } - .taxes { - max-width: 10em; - border: $border-thin-light; + .header { text-align: right; - padding: .5em !important; - - & > p { - font-size: 1.2em; - margin: .2em; + & > div { + margin-bottom: $spacing-xs; } } - vn-horizontal.header { - justify-content: flex-end; - margin-bottom: 0.5em; - } } \ No newline at end of file diff --git a/modules/order/front/prices-popover/index.html b/modules/order/front/prices-popover/index.html index a88e027ac..2a6f978fb 100644 --- a/modules/order/front/prices-popover/index.html +++ b/modules/order/front/prices-popover/index.html @@ -1,5 +1,5 @@ -
+
-
- -
{{$ctrl.item.id}}
-
- - - - - - - - - - - - - -
- - - - - - {{::price.warehouse}} - - - -
- {{::price.grouping}} - x {{::price.price | currency: 'EUR': 2}} -
-
- {{price.priceKg | currency: 'EUR'}}/Kg -
-
- - - - -
-
-
-
- - Wrong quantity - -
-
- - - - - - - - +
+
+
{{$ctrl.item.name}}
+ + + + + + +
+ +
+
+ + + + + + {{::price.warehouse}} + + + +
+ + {{::price.grouping}} + + x {{::price.price | currency: 'EUR': 2}} +
+
+ {{price.priceKg | currency: 'EUR'}}/Kg +
+
+ + + + +
+
+
+ +
diff --git a/modules/order/front/prices-popover/index.js b/modules/order/front/prices-popover/index.js index 3ce4050ce..40590b8bb 100644 --- a/modules/order/front/prices-popover/index.js +++ b/modules/order/front/prices-popover/index.js @@ -1,24 +1,23 @@ import ngModule from '../module'; +import Component from 'core/lib/component'; import './style.scss'; -class Controller { - constructor($scope, $http, $timeout, $element, $translate, vnApp) { - this.$ = $scope; - this.$timeout = $timeout; - this.$http = $http; - this.$element = $element; - this.$translate = $translate; - this.vnApp = vnApp; +class Controller extends Component { + constructor($element, $) { + super($element, $); this.totalBasquet = 0; } + set prices(value) { this._prices = value; if (value && value[0].grouping) this.calculateTotal(); } + get prices() { return this._prices; } + getTags() { let filter = { where: {itemFk: this.item.id, @@ -40,6 +39,7 @@ class Controller { }); }); } + show(event, item) { this.item = JSON.parse(JSON.stringify(item)); this.prices = this.item.prices; @@ -48,15 +48,18 @@ class Controller { this.$.popover.show(); this.$.popover.relocate(); } + clear() { this.item = {}; this.tags = {}; this._prices = {}; this.total = 0; } + calculateMax() { this.max = this.item.available - this.total; } + calculateTotal() { this.total = 0; @@ -73,7 +76,9 @@ class Controller { this.validate(); } + validate() { + /* this.$timeout(() => { this.calculateTotal(); let inputs = this.$element[0].querySelectorAll('vn-input-number[name="quantity"] div.infix:not(.validated)'); @@ -91,7 +96,9 @@ class Controller { else this.$element[0].querySelector('vn-vertical.prices').classList.remove('invalid'); }); + */ } + getFilledLines() { let filledLines = []; let match; @@ -110,6 +117,7 @@ class Controller { }); return filledLines; } + submit() { this.calculateTotal(); let filledLines = this.getFilledLines(); @@ -128,14 +136,14 @@ class Controller { this.$http.post(`OrderRows/addToOrder`, params).then(res => { this.vnApp.showSuccess(this.$translate.instant('Data saved!')); this.$.popover.hide(); - this.card.reload(); + + if (this.card) + this.card.reload(); }); }); } } -Controller.$inject = ['$scope', '$http', '$timeout', '$element', '$translate', 'vnApp']; - ngModule.component('vnOrderPricesPopover', { template: require('./index.html'), controller: Controller, @@ -143,6 +151,6 @@ ngModule.component('vnOrderPricesPopover', { order: '<' }, require: { - card: '^vnOrderCard' + card: '?^vnOrderCard' } }); diff --git a/modules/order/front/prices-popover/style.scss b/modules/order/front/prices-popover/style.scss index a904d1642..150c2296a 100644 --- a/modules/order/front/prices-popover/style.scss +++ b/modules/order/front/prices-popover/style.scss @@ -1,79 +1,44 @@ @import "variables"; -vn-order-prices-popover { - width: 150px; +.vn-order-prices-popover { display: block; + img[ng-src] { height: 100%; width: 100%; } - - .prices, .data{ - width: 18em; - } - - vn-vertical.data{ + vn-vertical.data { padding-right: 16px; border-right: 1px solid $color-main; } - - vn-vertical.prices{ - padding-left: 16px; - &.invalid { - vn-one.error { - display: block; - padding-top: 10px; - color: #d50000; - text-align: center!important; + .prices { + vn-table { + .warehouse { + width: 3em; + max-width: 3em; + } + .price-kg { + color: $color-font-secondary; + font-size: .8em + } + .vn-input-number { + width: 3.5em; } } + .footer { + text-align: center; - vn-tr { - border-bottom: 0 + .error { + display: none; + } + &.invalid { + .error { + display: block; + padding-top: 10px; + color: $color-alert; + text-align: center; + } + } } - - vn-tr > vn-td:first-child { - vertical-align: top - } - - vn-tr > vn-td:nth-child(3) { - vertical-align: top; - padding-top: 0 - } - - .priceKg { - color: $color-font-secondary; - font-size: .8em - } - } - - vn-input-number{ - margin: 0!important; - - label { - display: none; - } - } - - vn-one.number { - text-align: right; - padding-right: 8px; - } - vn-one.text{ - padding-top:10px!important; - } - vn-horizontal.buttons-bar{ - padding-top: 16px; - text-align: center; - } - .quicklinks vn-icon { - font-size: 1.8em !important; - padding: 0 !important; - & > i { - line-height: 36px - } - } - vn-one.error{ - display: none; } } \ No newline at end of file diff --git a/modules/order/front/volume/index.html b/modules/order/front/volume/index.html index e10b366fb..9dc1b811f 100644 --- a/modules/order/front/volume/index.html +++ b/modules/order/front/volume/index.html @@ -1,59 +1,60 @@ - + data="rows" + on-data-change="$ctrl.onDataChange()"> - + - - -
- - - - -
-
- - - - Item - Description - Quantity - m³ per quantity - - - - - - - {{::row.itemFk}} - - - - - - - {{::row.quantity}} - {{::row.volume | number:3}} - - - -
- + + + +
-
- + + + + + Item + Description + Quantity + m³ per quantity + + + + + + + {{::row.itemFk}} + + + + + + + {{::row.quantity}} + {{::row.volume | number:3}} + + + + + + + diff --git a/modules/order/front/volume/style.scss b/modules/order/front/volume/style.scss index baeabf383..da13eca0d 100644 --- a/modules/order/front/volume/style.scss +++ b/modules/order/front/volume/style.scss @@ -1,8 +1,12 @@ @import "./variables"; -.totalBox { - border: $border-thin-light; - text-align: left; - align-self: flex-end; +vn-order-volume { + .header { + text-align: right; + + & > div { + margin-bottom: $spacing-xs; + } + } } diff --git a/modules/ticket/front/descriptor/style.scss b/modules/ticket/front/descriptor/style.scss index 72cb80143..e0abcbc50 100644 --- a/modules/ticket/front/descriptor/style.scss +++ b/modules/ticket/front/descriptor/style.scss @@ -20,7 +20,7 @@ vn-dialog.modal-form { & > div { padding: 0 !important; } - vn-textfield { + .vn-textfield { width: 100%; } .buttons { diff --git a/modules/ticket/front/dms/create/index.js b/modules/ticket/front/dms/create/index.js index 39c372c9d..cb39be7dc 100644 --- a/modules/ticket/front/dms/create/index.js +++ b/modules/ticket/front/dms/create/index.js @@ -1,5 +1,4 @@ import ngModule from '../../module'; -import './style.scss'; class Controller { constructor($scope, $http, $state, $translate, vnApp, vnConfig) { diff --git a/modules/ticket/front/dms/create/style.scss b/modules/ticket/front/dms/create/style.scss deleted file mode 100644 index b47544b12..000000000 --- a/modules/ticket/front/dms/create/style.scss +++ /dev/null @@ -1,7 +0,0 @@ -vn-ticket-request { - vn-textfield { - margin: 0!important; - max-width: 100px; - } -} - diff --git a/modules/ticket/front/dms/edit/index.js b/modules/ticket/front/dms/edit/index.js index 31e797b9c..9ff967816 100644 --- a/modules/ticket/front/dms/edit/index.js +++ b/modules/ticket/front/dms/edit/index.js @@ -1,5 +1,4 @@ import ngModule from '../../module'; -import './style.scss'; class Controller { constructor($scope, $http, $state, $translate, vnApp) { diff --git a/modules/ticket/front/dms/edit/style.scss b/modules/ticket/front/dms/edit/style.scss deleted file mode 100644 index b47544b12..000000000 --- a/modules/ticket/front/dms/edit/style.scss +++ /dev/null @@ -1,7 +0,0 @@ -vn-ticket-request { - vn-textfield { - margin: 0!important; - max-width: 100px; - } -} - diff --git a/modules/ticket/front/request/create/style.scss b/modules/ticket/front/request/create/style.scss index b47544b12..73f136fc1 100644 --- a/modules/ticket/front/request/create/style.scss +++ b/modules/ticket/front/request/create/style.scss @@ -1,5 +1,5 @@ vn-ticket-request { - vn-textfield { + .vn-textfield { margin: 0!important; max-width: 100px; } diff --git a/modules/ticket/front/sale/style.scss b/modules/ticket/front/sale/style.scss index 2a18e0920..1eb7556e9 100644 --- a/modules/ticket/front/sale/style.scss +++ b/modules/ticket/front/sale/style.scss @@ -29,7 +29,7 @@ vn-ticket-sale { &>div{ padding: 0!important; } - vn-textfield { + .vn-textfield { width: 100%; } .buttons{ @@ -55,7 +55,7 @@ vn-ticket-sale { } } .vn-popover .transfer { - vn-textfield { + .vn-textfield { margin: 0 } vn-horizontal { diff --git a/modules/ticket/front/services/index.html b/modules/ticket/front/services/index.html index d9059e8e5..17b7eaeba 100644 --- a/modules/ticket/front/services/index.html +++ b/modules/ticket/front/services/index.html @@ -82,7 +82,8 @@ + ng-model="$ctrl.newServiceType.name" + vn-focus> diff --git a/modules/ticket/front/services/index.js b/modules/ticket/front/services/index.js index d070740f6..3082878a6 100644 --- a/modules/ticket/front/services/index.js +++ b/modules/ticket/front/services/index.js @@ -42,8 +42,6 @@ class Controller { onNewServiceTypeOpen() { this.newServiceType = {}; - this.nameInput = this.$element[0].querySelector('.edit input'); - this.nameInput.focus(); } newServiceTypeDialog(elementIndex, event) {