vnDialog opens in body, nightmare extensions with detailed errors
This commit is contained in:
parent
47998aaa97
commit
1b2c383502
|
@ -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);
|
||||
});
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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();
|
||||
});
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
ng-click="$ctrl.onClear($event)">
|
||||
</vn-icon>
|
||||
<vn-icon
|
||||
ng-if="::$ctrl.info"
|
||||
ng-if="::$ctrl.info != null"
|
||||
icon="info_outline"
|
||||
vn-tooltip="{{::$ctrl.info}}">
|
||||
</vn-icon>
|
||||
|
|
|
@ -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'),
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
@import "effects";
|
||||
|
||||
vn-autocomplete.vn-field {
|
||||
.vn-autocomplete {
|
||||
overflow: hidden;
|
||||
|
||||
& > .container {
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
vn-button-menu {
|
||||
.vn-button-menu {
|
||||
position: relative;
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
@import "variables";
|
||||
|
||||
vn-calendar {
|
||||
.vn-calendar {
|
||||
display: block;
|
||||
|
||||
& > div {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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'));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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(`<input type="date"></input>`)($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,
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
@import "variables";
|
||||
|
||||
.flatpickr-months .flatpickr-month,
|
||||
.flatpickr-weekdays,
|
||||
span.flatpickr-weekday {
|
||||
background-color: $color-main;
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -4,31 +4,12 @@ describe('Component vnDialog', () => {
|
|||
|
||||
beforeEach(ngModule('vnCore'));
|
||||
|
||||
beforeEach(angular.mock.inject($componentController => {
|
||||
$element = angular.element('<vn-dialog></vn-dialog>');
|
||||
controller = $componentController('vnDialog', {$element, $transclude: null});
|
||||
beforeEach(angular.mock.inject(($rootScope, $compile) => {
|
||||
$element = $compile('<vn-dialog><tpl-body>Body</tpl-body></vn-dialog>')($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');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
<vn-popover
|
||||
vn-id="popover"
|
||||
on-open="$ctrl.onOpen()"
|
||||
on-close="$ctrl.onClose()"
|
||||
on-close-start="$ctrl.emit('closeStart')">
|
||||
<div class="vn-drop-down">
|
||||
<div ng-show="$ctrl.showFilter" class="filter">
|
||||
<vn-textfield
|
||||
vn-id="input"
|
||||
ng-model="$ctrl.search"
|
||||
class="dense search"
|
||||
ng-blur="$ctrl.onFocusOut()"
|
||||
placeholder="{{::'Search' | translate}}">
|
||||
</vn-textfield>
|
||||
</div>
|
||||
<div vn-id="list" class="list" tabindex="-1">
|
||||
<ul
|
||||
vn-id="ul"
|
||||
class="dropdown"
|
||||
ng-click="$ctrl.onContainerClick($event)">
|
||||
</ul>
|
||||
<div
|
||||
ng-if="$ctrl.statusText"
|
||||
ng-click="$ctrl.onLoadMoreClick($event)"
|
||||
class="status"
|
||||
translate>
|
||||
{{$ctrl.statusText}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</vn-popover>
|
|
@ -0,0 +1,21 @@
|
|||
<div ng-show="$ctrl.showFilter" class="filter">
|
||||
<vn-textfield
|
||||
ng-model="$ctrl.search"
|
||||
class="dense search"
|
||||
ng-blur="$ctrl.onFocusOut()"
|
||||
placeholder="{{::'Search' | translate}}">
|
||||
</vn-textfield>
|
||||
</div>
|
||||
<div class="list" tabindex="-1">
|
||||
<ul
|
||||
class="dropdown"
|
||||
ng-click="$ctrl.onContainerClick($event)">
|
||||
</ul>
|
||||
<div
|
||||
ng-if="$ctrl.statusText"
|
||||
ng-click="$ctrl.onLoadMoreClick($event)"
|
||||
class="status"
|
||||
translate>
|
||||
{{$ctrl.statusText}}
|
||||
</div>
|
||||
</div>
|
|
@ -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: '<?',
|
||||
order: '@?',
|
||||
limit: '<?',
|
||||
searchFunction: '&?'
|
||||
},
|
||||
transclude: {
|
||||
tplItem: '?tplItem'
|
||||
searchFunction: '&?',
|
||||
searchDelay: '<?'
|
||||
}
|
||||
});
|
|
@ -1,7 +1,7 @@
|
|||
@import "effects";
|
||||
@import "variables";
|
||||
|
||||
.vn-drop-down {
|
||||
.vn-drop-down > .window > .content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: inherit;
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
ng-click="$ctrl.onClear($event)">
|
||||
</vn-icon>
|
||||
<vn-icon
|
||||
ng-if="::$ctrl.info"
|
||||
ng-if="::$ctrl.info != null"
|
||||
icon="info_outline"
|
||||
vn-tooltip="{{::$ctrl.info}}">
|
||||
</vn-icon>
|
||||
|
|
|
@ -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'];
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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', {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
@import "effects";
|
||||
|
||||
vn-icon-button {
|
||||
.vn-icon-button {
|
||||
@extend %clickable-light;
|
||||
color: $color-main;
|
||||
|
||||
|
|
|
@ -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');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
ng-click="$ctrl.onClear($event)">
|
||||
</vn-icon>
|
||||
<vn-icon
|
||||
ng-if="::$ctrl.info"
|
||||
ng-if="::$ctrl.info != null"
|
||||
icon="info_outline"
|
||||
vn-tooltip="{{::$ctrl.info}}">
|
||||
</vn-icon>
|
||||
|
|
|
@ -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
|
||||
});
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
vn-multi-check {
|
||||
vn-check {
|
||||
.vn-check {
|
||||
margin-bottom: 0.8em
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
<div ng-mousedown="$ctrl.onBgMouseDown($event)">
|
||||
<div
|
||||
class="window"
|
||||
ng-mousedown="$ctrl.onWindowMouseDown($event)">
|
||||
<div class="arrow"></div>
|
||||
<div class="content" ng-transclude></div>
|
||||
</div>
|
||||
</div>
|
|
@ -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
|
||||
});
|
|
@ -1,6 +0,0 @@
|
|||
<div class="vn-popover">
|
||||
<div class="popover">
|
||||
<div class="arrow"></div>
|
||||
<div class="content"></div>
|
||||
</div>
|
||||
</div>
|
|
@ -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
|
||||
});
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
vn-range {
|
||||
.vn-range {
|
||||
& > label {
|
||||
font-size: 12px;
|
||||
|
||||
|
|
|
@ -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});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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(`<vn-textfield><input></input></vn-textfield>`);
|
||||
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'}));
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -169,11 +169,11 @@ vn-table {
|
|||
}
|
||||
}
|
||||
}
|
||||
vn-textfield {
|
||||
.vn-textfield {
|
||||
float: right;
|
||||
margin: 0!important;
|
||||
}
|
||||
vn-check {
|
||||
.vn-check {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
@import "effects";
|
||||
|
||||
vn-wday-picker {
|
||||
.vn-wday-picker {
|
||||
text-align: center;
|
||||
|
||||
&:focus {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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]);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
|
@ -17,9 +17,9 @@ describe('Directive dialog', () => {
|
|||
});
|
||||
};
|
||||
|
||||
beforeEach(angular.mock.inject($componentController => {
|
||||
$element = angular.element('<div></div>');
|
||||
controller = $componentController('vnDialog', {$element: $element, $transclude: null});
|
||||
beforeEach(angular.mock.inject(($rootScope, $compile) => {
|
||||
$element = $compile('<vn-dialog><tpl-body></tpl-body></vn-dialog>')($rootScope);
|
||||
controller = $element.controller('vnDialog');
|
||||
}));
|
||||
|
||||
it('should call show() function if dialog is a instance of vnDialog', () => {
|
||||
|
|
|
@ -25,7 +25,7 @@ export function directive($timeout) {
|
|||
}
|
||||
|
||||
function onKeyDown(event) {
|
||||
if (event.keyCode === 27)
|
||||
if (event.key === 'Escape')
|
||||
destroyContainers();
|
||||
}
|
||||
|
||||
|
|
|
@ -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'
|
||||
];
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
|
||||
const regex = /Android|webOS|iPhone|iPad|iPod|BlackBerry|Windows Phone/i;
|
||||
const isMobile = regex.test(navigator.userAgent);
|
||||
export default isMobile;
|
|
@ -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
|
|
@ -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;
|
||||
|
|
|
@ -52,3 +52,4 @@ List: Listado
|
|||
# Misc
|
||||
|
||||
Phone: Teléfono
|
||||
Id: Id
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ vn-dialog.modal-form {
|
|||
& > div {
|
||||
padding: 0 !important;
|
||||
}
|
||||
vn-textfield {
|
||||
.vn-textfield {
|
||||
width: 100%;
|
||||
}
|
||||
.buttons {
|
||||
|
|
|
@ -23,7 +23,7 @@ vn-zone-calendar {
|
|||
flex-wrap: wrap;
|
||||
justify-content: space-evenly;
|
||||
|
||||
& > vn-calendar {
|
||||
& > .vn-calendar {
|
||||
max-width: 18em;
|
||||
|
||||
.day {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -9,7 +9,7 @@ vn-claim-action {
|
|||
flex: 1
|
||||
}
|
||||
|
||||
vn-check {
|
||||
.vn-check {
|
||||
flex: none;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
@import "variables";
|
||||
|
||||
vn-claim-detail {
|
||||
vn-textfield {
|
||||
.vn-textfield {
|
||||
margin: 0!important;
|
||||
max-width: 100px;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
vn-ticket-request {
|
||||
vn-textfield {
|
||||
.vn-textfield {
|
||||
margin: 0!important;
|
||||
max-width: 100px;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
vn-ticket-request {
|
||||
vn-textfield {
|
||||
.vn-textfield {
|
||||
margin: 0!important;
|
||||
max-width: 100px;
|
||||
}
|
||||
|
|
|
@ -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": {
|
||||
|
|
|
@ -8,7 +8,7 @@ vn-item-descriptor {
|
|||
display: block;
|
||||
}
|
||||
vn-dialog[vn-id=regularize]{
|
||||
vn-textfield{
|
||||
.vn-textfield{
|
||||
width: 100%
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,8 +22,9 @@
|
|||
</vn-autocomplete>
|
||||
<vn-autocomplete
|
||||
vn-one
|
||||
url="{{$ctrl.itemTypes}}"
|
||||
url="ItemTypes"
|
||||
label="Type"
|
||||
where="{categoryFk: filter.categoryFk}"
|
||||
show-field="name"
|
||||
value-field="id"
|
||||
ng-model="filter.typeFk">
|
||||
|
@ -42,13 +43,17 @@
|
|||
label="Buyer">
|
||||
</vn-autocomplete>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-check
|
||||
vn-one
|
||||
label="Active"
|
||||
ng-model="filter.isActive"
|
||||
triple-state="true">
|
||||
</vn-check>
|
||||
<vn-horizontal class="vn-pt-sm">
|
||||
<vn-one class="text-subtitle1" translate>
|
||||
Tags
|
||||
</vn-one>
|
||||
<vn-icon-button
|
||||
vn-none
|
||||
vn-bind="+"
|
||||
vn-tooltip="Add tag"
|
||||
icon="add_circle"
|
||||
ng-click="filter.tags.push({})">
|
||||
</vn-icon-button>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal ng-repeat="itemTag in filter.tags">
|
||||
<vn-autocomplete
|
||||
|
@ -61,14 +66,14 @@
|
|||
on-change="itemTag.value = null">
|
||||
</vn-autocomplete>
|
||||
<vn-textfield
|
||||
vn-two
|
||||
vn-one
|
||||
ng-show="tag.selection.isFree !== false"
|
||||
vn-id="text"
|
||||
label="Value"
|
||||
ng-model="itemTag.value">
|
||||
</vn-textfield>
|
||||
<vn-autocomplete
|
||||
vn-two
|
||||
vn-one
|
||||
ng-show="tag.selection.isFree === false"
|
||||
url="{{$ctrl.getSourceTable(tag.selection)}}"
|
||||
label="Value"
|
||||
|
@ -84,55 +89,65 @@
|
|||
tabindex="-1">
|
||||
</vn-icon-button>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-horizontal class="vn-pt-sm">
|
||||
<vn-one class="text-subtitle1" translate>
|
||||
More fields
|
||||
</vn-one>
|
||||
<vn-icon-button
|
||||
vn-none
|
||||
vn-bind="+"
|
||||
vn-tooltip="Add tag"
|
||||
vn-tooltip="Add field"
|
||||
icon="add_circle"
|
||||
ng-click="filter.tags.push({})">
|
||||
ng-click="$ctrl.fieldFilters.push({})">
|
||||
</vn-icon-button>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal class="vn-my-md">
|
||||
<span
|
||||
ng-click="$ctrl.initializeMoreFields()"
|
||||
vn-one translate
|
||||
class="unselectable"
|
||||
tabindex="-1"
|
||||
ng-class="{link: !filter.moreFields || !filter.moreFields.length}">
|
||||
More fields
|
||||
</span>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal ng-repeat="field in filter.moreFields">
|
||||
<vn-horizontal ng-repeat="fieldFilter in $ctrl.fieldFilters">
|
||||
<vn-autocomplete
|
||||
vn-one
|
||||
ng-model="field.field"
|
||||
data="$ctrl.moreFields"
|
||||
value-field="field"
|
||||
show-field="field"
|
||||
label="Field"
|
||||
on-change="field.value = null">
|
||||
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">
|
||||
</vn-autocomplete>
|
||||
<vn-textfield
|
||||
vn-two
|
||||
label="Value"
|
||||
ng-model="field.value">
|
||||
</vn-textfield>
|
||||
<vn-one ng-switch="info.type">
|
||||
<div ng-switch-when="Number">
|
||||
<vn-input-number
|
||||
label="Value"
|
||||
ng-model="fieldFilter.value">
|
||||
</vn-input-number>
|
||||
</div>
|
||||
<div ng-switch-when="Boolean">
|
||||
<vn-check
|
||||
label="Value"
|
||||
ng-model="fieldFilter.value">
|
||||
</vn-check>
|
||||
</div>
|
||||
<div ng-switch-when="Date">
|
||||
<vn-date-picker
|
||||
label="Value"
|
||||
ng-model="fieldFilter.value">
|
||||
</vn-date-picker>
|
||||
</div>
|
||||
<div ng-switch-default>
|
||||
<vn-textfield
|
||||
label="Value"
|
||||
ng-model="fieldFilter.value">
|
||||
</vn-textfield>
|
||||
</div>
|
||||
</vn-one>
|
||||
<vn-icon-button
|
||||
vn-none
|
||||
vn-tooltip="Remove field"
|
||||
icon="delete"
|
||||
ng-click="filter.moreFields.splice($index, 1)"
|
||||
ng-click="$ctrl.removeField($index, fieldFilter.name)"
|
||||
tabindex="-1">
|
||||
</vn-icon-button>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal ng-show="filter.moreFields && filter.moreFields.length">
|
||||
<vn-icon-button
|
||||
vn-bind="+"
|
||||
vn-tooltip="Add field"
|
||||
icon="add_circle"
|
||||
ng-click="filter.moreFields.push({})">
|
||||
</vn-icon-button>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal class="vn-mt-lg">
|
||||
<vn-submit label="Search"></vn-submit>
|
||||
</vn-horizontal>
|
||||
|
|
|
@ -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', {
|
||||
|
|
|
@ -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
|
|
@ -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: '&?'
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,111 +1,69 @@
|
|||
<vn-crud-model
|
||||
vn-id="model"
|
||||
url="Orders/CatalogFilter"
|
||||
filter="$ctrl.filter"
|
||||
params="{orderFk: $ctrl.$state.params.id}"
|
||||
limit="50"
|
||||
data="items"
|
||||
on-data-change="$ctrl.onDataChange()">
|
||||
</vn-crud-model>
|
||||
<div class="main-with-right-menu">
|
||||
<vn-card compact>
|
||||
<vn-horizontal class="catalog-header vn-px-md">
|
||||
<vn-one>
|
||||
<div ng-if="model.moreRows">
|
||||
<span translate>More than</span> {{model.limit}} <span translate>results</span>
|
||||
</div>
|
||||
</vn-one>
|
||||
<vn-auto>
|
||||
<vn-autocomplete vn-id="field" vn-one
|
||||
data="$ctrl.fieldList"
|
||||
initial-data="$ctrl.field"
|
||||
ng-model="$ctrl.field"
|
||||
translate-fields="['name']"
|
||||
order="name"
|
||||
show-field="name"
|
||||
value-field="field"
|
||||
label="Order by"
|
||||
disabled="!model.data">
|
||||
</vn-autocomplete>
|
||||
<vn-autocomplete vn-one
|
||||
data="$ctrl.wayList"
|
||||
initial-data="$ctrl.way"
|
||||
ng-model="$ctrl.way"
|
||||
translate-fields="['name']"
|
||||
show-field="name"
|
||||
value-field="way"
|
||||
label="Order"
|
||||
disabled="!model.data">
|
||||
</vn-autocomplete>
|
||||
</vn-auto>
|
||||
</vn-horizontal>
|
||||
</vn-card>
|
||||
<vn-card class="vn-mt-md">
|
||||
<vn-empty-rows ng-if="$ctrl.isRefreshing">
|
||||
<vn-spinner enable="$ctrl.isRefreshing"></vn-spinner>
|
||||
</vn-empty-rows>
|
||||
<vn-empty-rows ng-if="!$ctrl.isRefreshing && !model.data" translate>
|
||||
Enter a new search
|
||||
</vn-empty-rows>
|
||||
<vn-empty-rows ng-if="!$ctrl.isRefreshing && model.data.length === 0" translate>
|
||||
No results
|
||||
</vn-empty-rows>
|
||||
</vn-card>
|
||||
<vn-data-viewer
|
||||
model="model"
|
||||
class="main-with-right-menu">
|
||||
<vn-horizontal class="catalog-list">
|
||||
<section class="product" ng-repeat="item in items">
|
||||
<vn-card>
|
||||
<div class="image">
|
||||
<img
|
||||
ng-src="//verdnatura.es/vn-image-data/catalog/200x200/{{::item.image}}"
|
||||
zoom-image="//verdnatura.es/vn-image-data/catalog/1600x900/{{::item.image}}"
|
||||
on-error-src/>
|
||||
<section class="product" ng-repeat="item in items">
|
||||
<vn-card>
|
||||
<div class="image">
|
||||
<img
|
||||
ng-src="//verdnatura.es/vn-image-data/catalog/200x200/{{::item.image}}"
|
||||
zoom-image="//verdnatura.es/vn-image-data/catalog/1600x900/{{::item.image}}"
|
||||
on-error-src/>
|
||||
</div>
|
||||
<div class="description">
|
||||
<h3>
|
||||
{{::item.name}}
|
||||
</h3>
|
||||
<h4 class="ellipsize">
|
||||
<span translate-attr="::{title: item.subName}">{{::item.subName}}</span>
|
||||
</h4>
|
||||
<div class="tags">
|
||||
<vn-label-value
|
||||
ng-if="::item.value5"
|
||||
label="{{::item.tag5}}"
|
||||
value="{{::item.value5}}">
|
||||
</vn-label-value>
|
||||
<vn-label-value
|
||||
ng-if="::item.value6"
|
||||
label="{{::item.tag6}}"
|
||||
value="{{::item.value6}}">
|
||||
</vn-label-value>
|
||||
<vn-label-value
|
||||
ng-if="::item.value7"
|
||||
label="{{::item.tag7}}"
|
||||
value="{{::item.value7}}">
|
||||
</vn-label-value>
|
||||
</div>
|
||||
<div class="description">
|
||||
<h3>
|
||||
{{::item.name}}
|
||||
</h3>
|
||||
<h4 class="ellipsize">
|
||||
<span translate-attr="::{title: item.subName}">{{::item.subName}}</span>
|
||||
</h4>
|
||||
<div class="tags">
|
||||
<vn-label-value
|
||||
ng-if="::item.value5"
|
||||
label="{{::item.tag5}}"
|
||||
value="{{::item.value5}}">
|
||||
</vn-label-value>
|
||||
<vn-label-value
|
||||
ng-if="::item.value6"
|
||||
label="{{::item.tag6}}"
|
||||
value="{{::item.value6}}">
|
||||
</vn-label-value>
|
||||
<vn-label-value
|
||||
ng-if="::item.value7"
|
||||
label="{{::item.tag7}}"
|
||||
value="{{::item.value7}}">
|
||||
</vn-label-value>
|
||||
<div class="footer">
|
||||
<div class="price">
|
||||
<vn-one>
|
||||
<span>{{::item.available}}</span>
|
||||
<span translate>from</span>
|
||||
<span>{{::item.price | currency:'EUR':2}}</span>
|
||||
</vn-one>
|
||||
<vn-icon-button vn-none
|
||||
icon="add_circle"
|
||||
ng-click="$ctrl.preview($event, item)"
|
||||
vn-tooltip="Add">
|
||||
</vn-icon-button>
|
||||
</div>
|
||||
<div class="footer">
|
||||
<div class="price">
|
||||
<vn-one>
|
||||
<span>{{::item.available}}</span>
|
||||
<span translate>from</span>
|
||||
<span>{{::item.price | currency:'EUR':2}}</span>
|
||||
</vn-one>
|
||||
<vn-icon-button vn-none
|
||||
icon="add_circle"
|
||||
ng-click="$ctrl.preview($event, item)"
|
||||
vn-tooltip="Add">
|
||||
</vn-icon-button>
|
||||
</div>
|
||||
<div class="priceKg" ng-show="::item.priceKg">
|
||||
<span>Precio por kilo {{::item.priceKg | currency: 'EUR'}}</span>
|
||||
</div>
|
||||
<div class="priceKg" ng-show="::item.priceKg">
|
||||
<span>Precio por kilo {{::item.priceKg | currency: 'EUR'}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</vn-card>
|
||||
</section>
|
||||
</div>
|
||||
</vn-card>
|
||||
</section>
|
||||
</vn-horizontal>
|
||||
<vn-pagination class="vn-my-sm" model="model"></vn-pagination>
|
||||
</div>
|
||||
</vn-data-viewer>
|
||||
<vn-side-menu side="right">
|
||||
<vn-catalog-filter order="$ctrl.order"></vn-catalog-filter>
|
||||
</vn-side-menu>
|
||||
|
|
|
@ -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'];
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import ngModule from '../module';
|
||||
import './style.scss';
|
||||
|
||||
class Controller {
|
||||
constructor($translate, $scope, vnApp, $http, $state) {
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
vn-label-value[label=Total]{
|
||||
padding-top: 10px;
|
||||
display: block;
|
||||
font-size: 1.2em;
|
||||
}
|
|
@ -7,19 +7,20 @@
|
|||
<div>
|
||||
<vn-horizontal class="item-category">
|
||||
<vn-one ng-repeat="category in categories">
|
||||
<vn-icon
|
||||
ng-class="{'active': $ctrl.category.id == category.id}"
|
||||
icon="{{::category.icon}}"
|
||||
vn-tooltip="{{::category.name}}"
|
||||
ng-click="$ctrl.category = {
|
||||
id: category.id,
|
||||
value: category.name
|
||||
}">
|
||||
</vn-icon>
|
||||
<vn-icon
|
||||
ng-class="{'active': $ctrl.category.id == category.id}"
|
||||
icon="{{::category.icon}}"
|
||||
vn-tooltip="{{::category.name}}"
|
||||
ng-click="$ctrl.category = {
|
||||
id: category.id,
|
||||
value: category.name
|
||||
}">
|
||||
</vn-icon>
|
||||
</vn-one>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal class="input">
|
||||
<vn-autocomplete vn-id="type" vn-one
|
||||
<vn-vertical class="input">
|
||||
<vn-autocomplete
|
||||
vn-id="type"
|
||||
data="$ctrl.itemTypes"
|
||||
on-change="$ctrl.type = {
|
||||
id: value,
|
||||
|
@ -30,20 +31,38 @@
|
|||
value-field="id"
|
||||
label="Type">
|
||||
<prepend>
|
||||
<i class="material-icons">search</i>
|
||||
<vn-icon icon="search"></vn-icon>
|
||||
</prepend>
|
||||
<append>
|
||||
<i class="material-icons"
|
||||
ng-click="$ctrl.openPanel($event)"
|
||||
style="cursor: pointer; color: #aaa">
|
||||
keyboard_arrow_down
|
||||
</i>
|
||||
</append>
|
||||
</vn-autocomplete>
|
||||
</vn-horizontal>
|
||||
<vn-vertical class="input">
|
||||
</vn-vertical>
|
||||
<vn-vertical class="input vn-pt-md">
|
||||
<vn-autocomplete
|
||||
vn-id="field"
|
||||
data="$ctrl.catalog.orderFields"
|
||||
ng-model="$ctrl.catalog.orderField"
|
||||
selection="$ctrl.catalog.orderSelection"
|
||||
translate-fields="['name']"
|
||||
order="name"
|
||||
show-field="name"
|
||||
value-field="field"
|
||||
label="Order by"
|
||||
disabled="!model.data">
|
||||
</vn-autocomplete>
|
||||
<vn-autocomplete
|
||||
data="$ctrl.catalog.orderWays"
|
||||
ng-model="$ctrl.catalog.orderWay"
|
||||
translate-fields="['name']"
|
||||
show-field="name"
|
||||
value-field="way"
|
||||
label="Order"
|
||||
disabled="!model.data">
|
||||
</vn-autocomplete>
|
||||
<div ng-if="false && model.moreRows">
|
||||
<span translate>More than</span> {{model.limit}} <span translate>results</span>
|
||||
</div>
|
||||
</vn-vertical>
|
||||
<vn-vertical class="input vn-pt-md">
|
||||
<vn-textfield
|
||||
vn-one
|
||||
ng-keyUp="$ctrl.onSearchById($event)"
|
||||
label="Item id"
|
||||
ng-model="$ctrl.itemFk">
|
||||
|
@ -58,21 +77,24 @@
|
|||
label="Search tag"
|
||||
ng-model="$ctrl.value">
|
||||
<prepend>
|
||||
<i class="material-icons">search</i>
|
||||
<vn-icon icon="search"></vn-icon>
|
||||
</prepend>
|
||||
<append>
|
||||
<i class="material-icons"
|
||||
ng-click="$ctrl.openPanel($event)"
|
||||
style="cursor: pointer; color: #aaa">
|
||||
keyboard_arrow_down
|
||||
</i>
|
||||
<vn-icon
|
||||
icon="keyboard_arrow_down"
|
||||
ng-click="$ctrl.openPanel($event)"
|
||||
style="cursor: pointer;">
|
||||
</vn-icon>
|
||||
</append>
|
||||
</vn-textfield>
|
||||
</vn-vertical>
|
||||
<vn-popover
|
||||
vn-id="popover"
|
||||
on-close="$ctrl.onPopoverClose()">
|
||||
<vn-order-catalog-search-panel/>
|
||||
<vn-order-catalog-search-panel
|
||||
filter="panelFilter"
|
||||
on-submit="$ctrl.onPanelSubmit($filter)">
|
||||
</vn-order-catalog-search-panel>
|
||||
</vn-popover>
|
||||
<div class="chips">
|
||||
<vn-chip
|
||||
|
|
|
@ -5,7 +5,7 @@ class Controller {
|
|||
constructor($element, $http, $scope, $state, $compile, $transitions) {
|
||||
this.$element = $element;
|
||||
this.$http = $http;
|
||||
this.$scope = $scope;
|
||||
this.$ = $scope;
|
||||
this.$state = $state;
|
||||
this.$stateParams = $state.params;
|
||||
this.$compile = $compile;
|
||||
|
@ -28,7 +28,7 @@ class Controller {
|
|||
|
||||
this._order = value;
|
||||
|
||||
this.$scope.$applyAsync(() => {
|
||||
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(`<vn-order-catalog-search-panel/>`)(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
|
||||
*/
|
||||
|
|
|
@ -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'});
|
||||
});
|
||||
|
|
|
@ -2,77 +2,83 @@
|
|||
vn-id="watcher"
|
||||
data="$ctrl.rows">
|
||||
</vn-watcher>
|
||||
<vn-vertical>
|
||||
<vn-card class="vn-pa-lg">
|
||||
<vn-vertical>
|
||||
<vn-horizontal class="header">
|
||||
<vn-one class="taxes" ng-if="$ctrl.rows.length > 0">
|
||||
<p><vn-label translate>Subtotal</vn-label> {{$ctrl.subtotal | currency: 'EUR':2}}</p>
|
||||
<p><vn-label translate>VAT</vn-label> {{$ctrl.VAT | currency: 'EUR':2}}</p>
|
||||
<p><vn-label><strong>Total</strong></vn-label> <strong>{{$ctrl.order.total | currency: 'EUR':2}}</strong></p>
|
||||
</vn-one>
|
||||
</vn-horizontal>
|
||||
<vn-table>
|
||||
<vn-thead>
|
||||
<vn-tr>
|
||||
<vn-th></vn-th>
|
||||
<vn-th number>Id</vn-th>
|
||||
<vn-th>Description</vn-th>
|
||||
<vn-th>Warehouse</vn-th>
|
||||
<vn-th>Shipped</vn-th>
|
||||
<vn-th number>Quantity</vn-th>
|
||||
<vn-th number>Price</vn-th>
|
||||
<vn-th ng-if="!$ctrl.order.isConfirmed"></vn-th>
|
||||
</vn-tr>
|
||||
</vn-thead>
|
||||
<vn-tbody>
|
||||
<vn-tr ng-repeat="row in $ctrl.rows">
|
||||
<vn-td shrink>
|
||||
<img
|
||||
ng-src="//verdnatura.es/vn-image-data/catalog/50x50/{{::row.item.image}}"
|
||||
zoom-image="//verdnatura.es/vn-image-data/catalog/1600x900/{{::row.item.image}}"
|
||||
on-error-src/>
|
||||
</vn-td>
|
||||
<vn-td number>
|
||||
<span ng-click="$ctrl.showDescriptor($event, row.itemFk)"
|
||||
class="link">
|
||||
{{::row.itemFk | zeroFill:6}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td expand>
|
||||
<vn-fetched-tags
|
||||
max-length="6"
|
||||
item="::row.item"
|
||||
name="::row.item.name"
|
||||
sub-name="::row.item.subName">
|
||||
</vn-fetched-tags>
|
||||
</vn-td>
|
||||
<vn-td>{{::row.warehouse.name}}</vn-td>
|
||||
<vn-td>{{::row.shipped | date: 'dd/MM/yyyy'}}</vn-td>
|
||||
<vn-td number>{{::row.quantity}}</vn-td>
|
||||
<vn-td number>
|
||||
{{::row.price | currency: 'EUR':2}}
|
||||
</vn-td>
|
||||
<vn-td shrink ng-if="!$ctrl.order.isConfirmed">
|
||||
<vn-icon-button
|
||||
vn-tooltip="Remove item"
|
||||
icon="delete"
|
||||
ng-click="$ctrl.showDeleteRow($index)"
|
||||
tabindex="-1">
|
||||
</vn-icon-button>
|
||||
</vn-td>
|
||||
</vn-tr>
|
||||
</vn-tbody>
|
||||
</vn-table>
|
||||
</vn-vertical>
|
||||
<vn-data-viewer data="$ctrl.rows" class="vn-w-lg">
|
||||
<vn-card class="vn-pa-lg header" ng-if="$ctrl.rows.length > 0">
|
||||
<div>
|
||||
<vn-label translate>Subtotal</vn-label>
|
||||
{{$ctrl.subtotal | currency: 'EUR':2}}
|
||||
</div>
|
||||
<div>
|
||||
<vn-label translate>VAT</vn-label>
|
||||
{{$ctrl.VAT | currency: 'EUR':2}}
|
||||
</div>
|
||||
<div>
|
||||
<vn-label>Total</vn-label>
|
||||
{{$ctrl.order.total | currency: 'EUR':2}}
|
||||
</div>
|
||||
</vn-card>
|
||||
<vn-button-bar ng-if="!$ctrl.order.isConfirmed">
|
||||
<vn-button
|
||||
label="Confirm"
|
||||
ng-click="$ctrl.save()">
|
||||
</vn-button>
|
||||
</vn-button-bar>
|
||||
</vn-vertical>
|
||||
<vn-card class="vn-mt-md">
|
||||
<vn-table>
|
||||
<vn-thead>
|
||||
<vn-tr>
|
||||
<vn-th></vn-th>
|
||||
<vn-th number>Id</vn-th>
|
||||
<vn-th>Description</vn-th>
|
||||
<vn-th>Warehouse</vn-th>
|
||||
<vn-th>Shipped</vn-th>
|
||||
<vn-th number>Quantity</vn-th>
|
||||
<vn-th number>Price</vn-th>
|
||||
<vn-th ng-if="!$ctrl.order.isConfirmed"></vn-th>
|
||||
</vn-tr>
|
||||
</vn-thead>
|
||||
<vn-tbody>
|
||||
<vn-tr ng-repeat="row in $ctrl.rows">
|
||||
<vn-td shrink>
|
||||
<img
|
||||
ng-src="//verdnatura.es/vn-image-data/catalog/50x50/{{::row.item.image}}"
|
||||
zoom-image="//verdnatura.es/vn-image-data/catalog/1600x900/{{::row.item.image}}"
|
||||
on-error-src/>
|
||||
</vn-td>
|
||||
<vn-td number>
|
||||
<span ng-click="$ctrl.showDescriptor($event, row.itemFk)"
|
||||
class="link">
|
||||
{{::row.itemFk | zeroFill:6}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td expand>
|
||||
<vn-fetched-tags
|
||||
max-length="6"
|
||||
item="::row.item"
|
||||
name="::row.item.name"
|
||||
sub-name="::row.item.subName">
|
||||
</vn-fetched-tags>
|
||||
</vn-td>
|
||||
<vn-td shrink>{{::row.warehouse.name}}</vn-td>
|
||||
<vn-td shrink>{{::row.shipped | date: 'dd/MM/yyyy'}}</vn-td>
|
||||
<vn-td number>{{::row.quantity}}</vn-td>
|
||||
<vn-td number>
|
||||
{{::row.price | currency: 'EUR':2}}
|
||||
</vn-td>
|
||||
<vn-td shrink ng-if="!$ctrl.order.isConfirmed">
|
||||
<vn-icon-button
|
||||
vn-tooltip="Remove item"
|
||||
icon="delete"
|
||||
ng-click="$ctrl.showDeleteRow($index)"
|
||||
tabindex="-1">
|
||||
</vn-icon-button>
|
||||
</vn-td>
|
||||
</vn-tr>
|
||||
</vn-tbody>
|
||||
</vn-table>
|
||||
</vn-card>
|
||||
</vn-data-viewer>
|
||||
<vn-float-button
|
||||
icon="check"
|
||||
vn-tooltip="Confirm"
|
||||
ng-click="$ctrl.save()"
|
||||
ng-if="!$ctrl.order.isConfirmed"
|
||||
fixed-bottom-right>
|
||||
</vn-float-button>
|
||||
<vn-item-descriptor-popover
|
||||
vn-id="descriptor">
|
||||
</vn-item-descriptor-popover>
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
<vn-popover vn-id="popover" on-close="$ctrl.clear()">
|
||||
<div class="vn-descriptor">
|
||||
<div class="vn-descriptor vn-order-prices-popover">
|
||||
<div class="header">
|
||||
<span></span>
|
||||
<a translate-attr="{title: 'Preview'}" ui-sref="item.card.summary({id: $ctrl.item.id})">
|
||||
|
@ -7,81 +7,73 @@
|
|||
</a>
|
||||
<span></span>
|
||||
</div>
|
||||
<div class="vn-pa-md">
|
||||
<vn-horizontal>
|
||||
<h5>{{$ctrl.item.id}}</h5>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-vertical class="data">
|
||||
<vn-auto>
|
||||
<vn-label-value label="Name"
|
||||
value="{{$ctrl.item.name}}">
|
||||
</vn-label-value>
|
||||
<vn-label-value label="Buyer"
|
||||
value="{{$ctrl.item.firstName}} {{$ctrl.item.lastName}}">
|
||||
</vn-label-value>
|
||||
<vn-label-value
|
||||
ng-repeat="tag in $ctrl.tags"
|
||||
label="{{::tag.tag.name}}"
|
||||
value="{{::tag.value}}">
|
||||
</vn-label-value>
|
||||
</vn-auto>
|
||||
<vn-icon-button
|
||||
class="button"
|
||||
label="Save"
|
||||
ng-click="$ctrl.saveQuantity($ctrl.prices)"></vn-icon-button>
|
||||
</vn-vertical>
|
||||
<vn-vertical class="prices">
|
||||
<form name="form">
|
||||
<vn-table>
|
||||
<vn-tbody>
|
||||
<vn-tr ng-repeat="price in $ctrl.prices">
|
||||
<vn-td shrink>
|
||||
<span class="ellipsize text"
|
||||
title="{{::price.warehouse}}">
|
||||
{{::price.warehouse}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td number shrink>
|
||||
<div>
|
||||
<span ng-click="$ctrl.addQuantity(price)"
|
||||
class="link unselectable">{{::price.grouping}}</span>
|
||||
<span> x {{::price.price | currency: 'EUR': 2}}</span>
|
||||
</div>
|
||||
<div class="priceKg" ng-show="::price.priceKg">
|
||||
{{price.priceKg | currency: 'EUR'}}/Kg
|
||||
</div>
|
||||
</vn-td>
|
||||
<vn-td>
|
||||
<vn-input-number
|
||||
min="0"
|
||||
name="quantity"
|
||||
label="Qty."
|
||||
ng-model="price.quantity"
|
||||
step="price.grouping"
|
||||
on-change="$ctrl.validate()">
|
||||
</vn-input-number>
|
||||
</vn-td>
|
||||
</vn-tr>
|
||||
</vn-tbody>
|
||||
</vn-table>
|
||||
</form>
|
||||
<vn-one class="error">
|
||||
<span translate>Wrong quantity</span>
|
||||
</vn-one>
|
||||
</vn-vertical>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal class="buttons-bar">
|
||||
<vn-quick-links
|
||||
links="$ctrl.quicklinks">
|
||||
</vn-quick-links>
|
||||
<vn-one>
|
||||
<vn-submit
|
||||
label="Save"
|
||||
ng-click="$ctrl.submit()">
|
||||
</vn-submit>
|
||||
</vn-one>
|
||||
</vn-horizontal>
|
||||
<div class="body vn-pa-md">
|
||||
<div class="attributes">
|
||||
<h5>{{$ctrl.item.name}}</h5>
|
||||
<vn-label-value
|
||||
label="Id"
|
||||
value="{{$ctrl.item.id}}">
|
||||
</vn-label-value>
|
||||
<vn-label-value
|
||||
label="Buyer"
|
||||
value="{{$ctrl.item.firstName}} {{$ctrl.item.lastName}}">
|
||||
</vn-label-value>
|
||||
<vn-label-value
|
||||
ng-repeat="tag in $ctrl.tags"
|
||||
label="{{::tag.tag.name}}"
|
||||
value="{{::tag.value}}">
|
||||
</vn-label-value>
|
||||
</div>
|
||||
<vn-quick-links
|
||||
links="$ctrl.quicklinks">
|
||||
</vn-quick-links>
|
||||
</div>
|
||||
<form name="form" class="prices">
|
||||
<vn-table>
|
||||
<vn-tbody>
|
||||
<vn-tr ng-repeat="price in $ctrl.prices">
|
||||
<vn-td shrink class="warehouse">
|
||||
<span
|
||||
class="ellipsize text"
|
||||
title="{{::price.warehouse}}">
|
||||
{{::price.warehouse}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td number expand>
|
||||
<div>
|
||||
<span
|
||||
ng-click="$ctrl.addQuantity(price)"
|
||||
class="link unselectable">
|
||||
{{::price.grouping}}
|
||||
</span>
|
||||
<span> x {{::price.price | currency: 'EUR': 2}}</span>
|
||||
</div>
|
||||
<div class="price-kg" ng-show="::price.priceKg">
|
||||
{{price.priceKg | currency: 'EUR'}}/Kg
|
||||
</div>
|
||||
</vn-td>
|
||||
<vn-td shrink>
|
||||
<vn-input-number
|
||||
min="0"
|
||||
name="quantity"
|
||||
ng-model="price.quantity"
|
||||
step="price.grouping"
|
||||
on-change="$ctrl.validate()"
|
||||
class="dense">
|
||||
</vn-input-number>
|
||||
</vn-td>
|
||||
</vn-tr>
|
||||
</vn-tbody>
|
||||
</vn-table>
|
||||
<div class="footer vn-pa-md">
|
||||
<div class="error">
|
||||
<span translate>Wrong quantity</span>
|
||||
</div>
|
||||
<vn-submit
|
||||
label="Save"
|
||||
ng-click="$ctrl.submit()">
|
||||
</vn-submit>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</vn-popover>
|
||||
|
|
|
@ -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'
|
||||
}
|
||||
});
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -1,59 +1,60 @@
|
|||
<vn-crud-model auto-load="false"
|
||||
<vn-crud-model
|
||||
auto-load="true"
|
||||
vn-id="model"
|
||||
url="OrderRows"
|
||||
filter="::$ctrl.filter"
|
||||
link="{orderFk: $ctrl.$stateParams.id}"
|
||||
limit="20"
|
||||
data="rows" on-data-change="$ctrl.onDataChange()">
|
||||
data="rows"
|
||||
on-data-change="$ctrl.onDataChange()">
|
||||
</vn-crud-model>
|
||||
<mg-ajax path="Orders/{{$ctrl.$stateParams.id}}/getTotalVolume" options="mgEdit"></mg-ajax>
|
||||
<vn-vertical>
|
||||
<vn-data-viewer model="model" class="header vn-w-lg">
|
||||
<vn-card class="vn-pa-lg">
|
||||
<vn-vertical>
|
||||
<vn-horizontal>
|
||||
<div class="totalBox">
|
||||
<vn-label-value label="Total"
|
||||
value="{{::edit.model.totalVolume}} M³">
|
||||
</vn-label-value>
|
||||
<vn-label-value label="Cajas"
|
||||
value="{{::edit.model.totalBoxes | dashIfEmpty}} U">
|
||||
</vn-label-value>
|
||||
</div>
|
||||
</vn-horizontal>
|
||||
<vn-table model="model">
|
||||
<vn-thead>
|
||||
<vn-tr>
|
||||
<vn-th field="itemFk" default-order="ASC" number>Item</vn-th>
|
||||
<vn-th>Description</vn-th>
|
||||
<vn-th field="quantity" number>Quantity</vn-th>
|
||||
<vn-th number>m³ per quantity</vn-th>
|
||||
</vn-tr>
|
||||
</vn-thead>
|
||||
<vn-tbody>
|
||||
<vn-tr ng-repeat="row in rows">
|
||||
<vn-td number>
|
||||
<span
|
||||
ng-click="$ctrl.showDescriptor($event, row.itemFk)"
|
||||
class="link">
|
||||
{{::row.itemFk}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td expand>
|
||||
<vn-fetched-tags
|
||||
max-length="6"
|
||||
item="::row.item"
|
||||
name="::row.item.name"
|
||||
sub-name="::row.item.subName">
|
||||
</vn-fetched-tags>
|
||||
</vn-td>
|
||||
<vn-td number>{{::row.quantity}}</vn-td>
|
||||
<vn-td number>{{::row.volume | number:3}}</vn-td>
|
||||
</vn-tr>
|
||||
</vn-tbody>
|
||||
</vn-table>
|
||||
</vn-vertical>
|
||||
<vn-pagination model="model"></vn-pagination>
|
||||
<vn-label-value
|
||||
label="Total"
|
||||
value="{{::edit.model.totalVolume}} M³">
|
||||
</vn-label-value>
|
||||
<vn-label-value
|
||||
label="Cajas"
|
||||
value="{{::edit.model.totalBoxes | dashIfEmpty}} U">
|
||||
</vn-label-value>
|
||||
</vn-card>
|
||||
</vn-vertical>
|
||||
<vn-item-descriptor-popover vn-id="descriptor"></vn-item-descriptor-popover>
|
||||
<vn-card class="vn-mt-md">
|
||||
<vn-table model="model">
|
||||
<vn-thead>
|
||||
<vn-tr>
|
||||
<vn-th field="itemFk" default-order="ASC" number>Item</vn-th>
|
||||
<vn-th>Description</vn-th>
|
||||
<vn-th field="quantity" number>Quantity</vn-th>
|
||||
<vn-th number>m³ per quantity</vn-th>
|
||||
</vn-tr>
|
||||
</vn-thead>
|
||||
<vn-tbody>
|
||||
<vn-tr ng-repeat="row in rows">
|
||||
<vn-td number>
|
||||
<span
|
||||
ng-click="$ctrl.showDescriptor($event, row.itemFk)"
|
||||
class="link">
|
||||
{{::row.itemFk}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td expand>
|
||||
<vn-fetched-tags
|
||||
max-length="6"
|
||||
item="::row.item"
|
||||
name="::row.item.name"
|
||||
sub-name="::row.item.subName">
|
||||
</vn-fetched-tags>
|
||||
</vn-td>
|
||||
<vn-td number>{{::row.quantity}}</vn-td>
|
||||
<vn-td number>{{::row.volume | number:3}}</vn-td>
|
||||
</vn-tr>
|
||||
</vn-tbody>
|
||||
</vn-table>
|
||||
</vn-card>
|
||||
</vn-data-viewer>
|
||||
<vn-item-descriptor-popover
|
||||
vn-id="descriptor">
|
||||
</vn-item-descriptor-popover>
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ vn-dialog.modal-form {
|
|||
& > div {
|
||||
padding: 0 !important;
|
||||
}
|
||||
vn-textfield {
|
||||
.vn-textfield {
|
||||
width: 100%;
|
||||
}
|
||||
.buttons {
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import ngModule from '../../module';
|
||||
import './style.scss';
|
||||
|
||||
class Controller {
|
||||
constructor($scope, $http, $state, $translate, vnApp, vnConfig) {
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
vn-ticket-request {
|
||||
vn-textfield {
|
||||
margin: 0!important;
|
||||
max-width: 100px;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
import ngModule from '../../module';
|
||||
import './style.scss';
|
||||
|
||||
class Controller {
|
||||
constructor($scope, $http, $state, $translate, vnApp) {
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
vn-ticket-request {
|
||||
vn-textfield {
|
||||
margin: 0!important;
|
||||
max-width: 100px;
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue