vnField stable & applied to all field except vnTextfield

This commit is contained in:
Juan Ferrer 2019-10-08 23:57:02 +02:00
parent 4f92cafe30
commit 757fc6fe23
73 changed files with 905 additions and 950 deletions

View File

@ -1,6 +1,6 @@
export default {
vnTextfield: 'vn-textfield > div > div > div > input',
vnInputNumber: 'vn-input-number > div > div > div > input',
vnTextfield: 'vn-textfield input',
vnInputNumber: 'vn-input-number input',
vnSubmit: 'vn-submit > input',
vnFloatButton: 'vn-float-button > button'
};

View File

@ -18,8 +18,18 @@ let actions = {
clearInput: function(selector, done) {
this.wait(selector)
.evaluate(inputSelector => {
return document.querySelector(inputSelector).closest('*[model], *[field], *[value]').$ctrl.value = '';
.evaluate(selector => {
let field = document.querySelector(selector)
.closest('*[model], *[field], *[value]');
let $ctrl = field.$ctrl;
if (field.classList.contains('vn-field')) {
$ctrl.field = null;
$ctrl.$.$apply();
} else
$ctrl.value = null;
$ctrl.input.dispatchEvent(new Event('change'));
}, selector)
.then(done)
.catch(done);
@ -167,8 +177,8 @@ let actions = {
focusElement: function(selector, done) {
this.wait(selector)
.evaluate_now(elemenetSelector => {
let element = document.querySelector(elemenetSelector);
.evaluate_now(selector => {
let element = document.querySelector(selector);
element.focus();
}, done, selector)
.then(done)
@ -401,8 +411,7 @@ let actions = {
},
autocompleteSearch: function(autocompleteSelector, searchValue, done) {
this.wait(`${autocompleteSelector} input`)
.waitToClick(`${autocompleteSelector} input`)
this.waitToClick(`${autocompleteSelector} input`)
.write(`.vn-popover.shown .vn-drop-down input`, searchValue)
.waitToClick(`.vn-popover.shown .vn-drop-down li.active`)
.wait((autocompleteSelector, searchValue) => {
@ -412,7 +421,7 @@ let actions = {
}, autocompleteSelector, searchValue)
.then(done)
.catch(() => {
done(new Error(`.autocompleteSearch() for ${autocompleteSelector}, timed out`));
done(new Error(`.autocompleteSearch() for value ${searchValue} in ${autocompleteSelector} timed out`));
});
},
@ -427,25 +436,22 @@ let actions = {
.catch(done);
},
datePicker: function(datePickerSelector, changeMonth, day, done) {
this.wait(datePickerSelector)
.mousedown(datePickerSelector)
.wait('div.flatpickr-calendar.open');
datePicker: function(selector, changeMonth, day, done) {
this.wait(selector)
.mousedown(`${selector} input`)
.wait('.flatpickr-calendar.open');
if (changeMonth > 0)
this.mousedown('body > div.flatpickr-calendar.open > div.flatpickr-months > span.flatpickr-next-month > svg');
this.mousedown(`.flatpickr-calendar.open .flatpickr-next-month`);
if (changeMonth < 0)
this.mousedown('body > div.flatpickr-calendar.open > div.flatpickr-months > span.flatpickr-prev-month > svg');
this.mousedown(`.flatpickr-calendar.open .flatpickr-prev-month`);
let daySelector;
if (!day)
daySelector = 'div.flatpickr-calendar.open span.flatpickr-day:nth-child(16)';
daySelector = `.flatpickr-calendar.open .flatpickr-day:nth-child(16)`;
if (day)
daySelector = `span.flatpickr-day[aria-label~="${day},"]:not(.prevMonthDay):not(.nextMonthDay)`;
daySelector = `.flatpickr-calendar.open .flatpickr-day[aria-label~="${day},"]:not(.prevMonthDay):not(.nextMonthDay)`;
this.wait(selector => {
return document.querySelector(selector);

View File

@ -16,9 +16,9 @@ export default {
userLocalCompany: '.user-configuration vn-autocomplete[field="$ctrl.localCompanyFk"]',
userWarehouse: '.user-configuration vn-autocomplete[field="$ctrl.warehouseFk"]',
userCompany: '.user-configuration vn-autocomplete[field="$ctrl.companyFk"]',
userConfigFirstAutocompleteClear: '#localWarehouse > div > div > div > vn-icon.clear',
userConfigSecondAutocompleteClear: '#localBank > div > div > div > vn-icon.clear',
userConfigThirdAutocompleteClear: '#localCompany > div > div > div > vn-icon.clear',
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]'
},
clientsIndex: {
@ -79,14 +79,14 @@ export default {
saveButton: `${components.vnSubmit}`
},
clientBillingData: {
payMethodAutocomplete: 'vn-autocomplete[field="$ctrl.client.payMethodFk"]',
IBANInput: `${components.vnTextfield}[name="iban"]`,
dueDayInput: `${components.vnInputNumber}[name="dueDay"]`,
receivedCoreLCRCheckbox: 'vn-check[label="Received LCR"]',
receivedCoreVNLCheckbox: 'vn-check[label="Received core VNL"]',
receivedB2BVNLCheckbox: 'vn-check[label="Received B2B VNL"]',
payMethodAutocomplete: 'vn-client-billing-data vn-autocomplete[field="$ctrl.client.payMethodFk"]',
IBANInput: `vn-client-billing-data ${components.vnTextfield}[name="iban"]`,
dueDayInput: `vn-client-billing-data ${components.vnInputNumber}[name="dueDay"]`,
receivedCoreLCRCheckbox: 'vn-client-billing-data vn-check[label="Received LCR"]',
receivedCoreVNLCheckbox: 'vn-client-billing-data vn-check[label="Received core VNL"]',
receivedB2BVNLCheckbox: 'vn-client-billing-data vn-check[label="Received B2B VNL"]',
swiftBicAutocomplete: 'vn-client-billing-data vn-autocomplete[field="$ctrl.client.bankEntityFk"]',
clearswiftBicButton: 'vn-client-billing-data vn-autocomplete[field="$ctrl.client.bankEntityFk"] > div > div > div > vn-icon > i',
clearswiftBicButton: 'vn-client-billing-data vn-autocomplete[field="$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',
@ -345,7 +345,7 @@ export default {
createTicketView: {
clientAutocomplete: 'vn-ticket-create vn-autocomplete[field="$ctrl.clientFk"]',
addressAutocomplete: 'vn-ticket-create vn-autocomplete[field="$ctrl.addressFk"]',
deliveryDateInput: 'vn-ticket-create > div > div > vn-card > div > vn-ticket-create-card > vn-date-picker > div > input',
deliveryDateInput: 'vn-ticket-create vn-date-picker[field="$ctrl.landed"]',
warehouseAutocomplete: 'vn-ticket-create vn-autocomplete[field="$ctrl.warehouseFk"]',
agencyAutocomplete: 'vn-ticket-create vn-autocomplete[field="$ctrl.ticket.agencyModeFk"]',
createButton: `${components.vnSubmit}`
@ -392,7 +392,7 @@ export default {
firstQuantityInput: 'vn-input-number[label="Quantity"] input',
firstRemovePackageButton: 'vn-icon-button[vn-tooltip="Remove package"]',
addPackageButton: 'vn-icon-button[vn-tooltip="Add package"]',
clearPackageAutocompleteButton: 'vn-autocomplete[label="Package"] > div > div > div > vn-icon > i',
clearPackageAutocompleteButton: 'vn-autocomplete[label="Package"] .icons > vn-icon[icon=clear]',
savePackagesButton: `${components.vnSubmit}`
},
ticketSales: {
@ -408,7 +408,7 @@ export default {
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[model="$ctrl.newDiscount"] input',
moreMenuUpdateDiscountInput: 'vn-ticket-sale vn-dialog form vn-ticket-sale-edit-discount vn-input-number[field="$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"]',
@ -416,11 +416,11 @@ export default {
firstSaleText: 'vn-table div > vn-tbody > vn-tr:nth-child(1)',
firstSaleThumbnailImage: 'vn-ticket-sale:nth-child(1) vn-tr:nth-child(1) vn-td:nth-child(3) > img',
firstSaleZoomedImage: 'body > div > div > img',
firstSaleQuantity: 'vn-input-number[model="sale.quantity"]:nth-child(1) input',
firstSaleQuantity: 'vn-input-number[field="sale.quantity"]:nth-child(1) input',
firstSaleQuantityCell: 'vn-ticket-sale vn-tr:nth-child(1) > vn-td-editable:nth-child(5)',
firstSaleQuantityClearInput: 'vn-textfield[model="sale.quantity"] div.suffix > i',
firstSaleIdInput: 'body > vn-app > div > ui-view > vn-ticket-card > vn-main-block > div > vn-ticket-sale > vn-vertical > vn-card > div > vn-vertical > vn-table > div > vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(4) > vn-autocomplete > div > div > input',
firstSaleIdAutocomplete: 'vn-ticket-sale > vn-vertical > vn-card > div > vn-vertical > vn-table > div > vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(4) > vn-autocomplete',
firstSaleIdInput: 'vn-ticket-sale vn-table vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(4) > vn-autocomplete input',
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',
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',
@ -438,10 +438,10 @@ export default {
secondSaleText: 'vn-table div > vn-tbody > vn-tr:nth-child(2)',
secondSaleId: 'vn-ticket-sale:nth-child(2) vn-td-editable:nth-child(4) text > span',
secondSaleIdCell: 'vn-ticket-sale vn-tr:nth-child(2) > vn-td-editable:nth-child(4)',
secondSaleIdInput: 'body > vn-app > div > ui-view > vn-ticket-card > vn-main-block > div > vn-ticket-sale > vn-vertical > vn-card > div > vn-vertical > vn-table > div > vn-tbody > vn-tr:nth-child(2) > vn-td:nth-child(4) > vn-autocomplete > div > div > input',
secondSaleIdAutocomplete: 'vn-ticket-sale > vn-vertical > vn-card > div > vn-vertical > vn-table > div > vn-tbody > vn-tr:nth-child(2) > vn-td:nth-child(4) > vn-autocomplete',
secondSaleIdInput: 'vn-ticket-sale vn-table vn-tbody > vn-tr:nth-child(2) > vn-td:nth-child(4) > vn-autocomplete input',
secondSaleIdAutocomplete: 'vn-ticket-sale vn-table vn-tbody > vn-tr:nth-child(2) > vn-td:nth-child(4) > vn-autocomplete',
secondSaleQuantity: 'vn-ticket-sale vn-table vn-tr:nth-child(2) vn-input-number input',
secondSaleConceptCell: 'vn-ticket-sale vn-table > div > vn-tbody > vn-tr:nth-child(2) > vn-td-editable:nth-child(6)',
secondSaleConceptCell: 'vn-ticket-sale vn-table vn-tbody > vn-tr:nth-child(2) > vn-td-editable:nth-child(6)',
secondSaleConceptInput: 'vn-ticket-sale vn-table vn-tr:nth-child(2) > vn-td-editable.ng-isolate-scope.selected vn-textfield input',
totalImport: 'vn-ticket-sale > vn-vertical > vn-card > div > vn-vertical > vn-horizontal > vn-one > p:nth-child(3) > strong',
selectAllSalesCheckbox: 'vn-ticket-sale vn-thead vn-check',
@ -485,8 +485,8 @@ export default {
request: 'vn-ticket-request-index > form > vn-card > div > vn-horizontal > vn-table > div > vn-tbody > vn-tr',
descriptionInput: 'vn-ticket-request-create > form > div > vn-card > div > vn-horizontal:nth-child(1) > vn-textfield > div > div > div.infix > input',
atenderAutocomplete: 'vn-ticket-request-create vn-autocomplete[field="$ctrl.ticketRequest.atenderFk"]',
quantityInput: 'vn-ticket-request-create > form > div > vn-card > div > vn-horizontal:nth-child(2) > vn-input-number:nth-child(1) > div > div > div.infix > input',
priceInput: 'vn-ticket-request-create > form > div > vn-card > div > vn-horizontal:nth-child(2) > vn-input-number:nth-child(2) > div > div > div.infix > input',
quantityInput: 'vn-ticket-request-create vn-input-number input[name=quantity]',
priceInput: 'vn-ticket-request-create vn-input-number input[name=price]',
firstRemoveRequestButton: 'vn-ticket-request-index vn-icon[icon="delete"]:nth-child(1)',
saveButton: 'vn-ticket-request-create > form > div > vn-button-bar > vn-submit[label="Create"] input',
firstDescription: 'vn-ticket-request-index > form > vn-card > div > vn-horizontal > vn-table > div > vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(2)',
@ -514,7 +514,7 @@ export default {
createStateView: {
stateAutocomplete: 'vn-autocomplete[field="$ctrl.stateFk"]',
workerAutocomplete: 'vn-autocomplete[field="$ctrl.workerFk"]',
clearStateInputButton: 'vn-autocomplete[field="$ctrl.stateFk"] > div > div > div > vn-icon > i',
clearStateInputButton: 'vn-autocomplete[field="$ctrl.stateFk"] .icons > vn-icon[icon=clear]',
saveStateButton: `${components.vnSubmit}`
},
claimsIndex: {
@ -548,12 +548,12 @@ export default {
},
claimDetail: {
secondItemDiscount: 'vn-claim-detail > vn-vertical > vn-card > div > vn-vertical > vn-table > div > vn-tbody > vn-tr:nth-child(2) > vn-td:nth-child(6) > span',
discountInput: '.vn-popover.shown vn-input-number[model="$ctrl.newDiscount"] > div > div > div.infix > input',
discountInput: '.vn-popover.shown vn-input-number[field="$ctrl.newDiscount"] > div > div > div.infix > 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',
claimDetailLine: 'vn-claim-detail > vn-vertical > vn-card > div > vn-vertical > vn-table > div > vn-tbody > vn-tr',
firstItemQuantityInput: 'vn-claim-detail vn-tr:nth-child(1) vn-input-number[model="saleClaimed.quantity"] input',
firstItemQuantityInput: 'vn-claim-detail vn-tr:nth-child(1) vn-input-number[field="saleClaimed.quantity"] input',
totalClaimed: 'vn-claim-detail > vn-vertical > vn-card > div > vn-vertical > vn-horizontal > div > vn-label-value:nth-child(2) > section > span',
secondItemDeleteButton: 'vn-claim-detail > vn-vertical > vn-card > div > vn-vertical > vn-table > div > vn-tbody > vn-tr:nth-child(2) > vn-td:nth-child(8) > vn-icon-button > button > vn-icon > i'
},
@ -597,7 +597,7 @@ export default {
clientAutocomplete: 'vn-autocomplete[label="Client"]',
addressAutocomplete: 'vn-autocomplete[label="Address"]',
agencyAutocomplete: 'vn-autocomplete[label="Agency"]',
landedDatePicker: 'vn-date-picker[label="Landed"] input',
landedDatePicker: 'vn-date-picker[label="Landed"]',
createButton: `${components.vnSubmit}`,
cancelButton: 'vn-button[href="#!/client/index"]'
},
@ -633,7 +633,7 @@ export default {
},
createRouteView: {
workerAutocomplete: 'vn-route-create vn-autocomplete[field="$ctrl.route.workerFk"]',
createdDatePicker: 'vn-route-create vn-date-picker[model="$ctrl.route.created"] > div > input',
createdDatePicker: 'vn-route-create vn-date-picker[field="$ctrl.route.created"]',
vehicleAutoComplete: 'vn-route-create vn-autocomplete[field="$ctrl.route.vehicleFk"]',
agencyAutoComplete: 'vn-route-create vn-autocomplete[field="$ctrl.route.agencyModeFk"]',
descriptionInput: 'vn-route-create vn-textfield[field="$ctrl.route.description"] input',
@ -650,10 +650,10 @@ export default {
vehicleAutoComplete: 'vn-route-basic-data vn-autocomplete[field="$ctrl.route.vehicleFk"]',
agencyAutoComplete: 'vn-route-basic-data vn-autocomplete[field="$ctrl.route.agencyModeFk"]',
kmStartInput: 'vn-route-basic-data vn-input-number[field="$ctrl.route.kmStart"] input',
kmEndInput: 'vn-route-basic-data vn-input-number[model="$ctrl.route.kmEnd"] input',
createdDateInput: 'vn-route-basic-data vn-date-picker[model="$ctrl.route.created"] > div > input',
startedHourInput: 'vn-route-basic-data vn-input-time[model="$ctrl.route.started"] input',
finishedHourInput: 'vn-route-basic-data vn-input-time[model="$ctrl.route.finished"] input',
kmEndInput: 'vn-route-basic-data vn-input-number[field="$ctrl.route.kmEnd"] input',
createdDateInput: 'vn-route-basic-data vn-date-picker[field="$ctrl.route.created"]',
startedHourInput: 'vn-route-basic-data vn-input-time[field="$ctrl.route.started"] input',
finishedHourInput: 'vn-route-basic-data vn-input-time[field="$ctrl.route.finished"] input',
saveButton: 'vn-route-basic-data vn-submit[label="Save"] input'
},
routeTickets: {

View File

@ -1,27 +0,0 @@
<div>
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
<input
type="button"
class="mdl-textfield__input"
ng-click="$ctrl.onMouseDown($event)"
ng-keydown="$ctrl.onKeyDown($event)"/>
<div class="icons">
<vn-icon
ng-show="!$ctrl.disabled"
icon="clear"
class="clear"
ng-click="$ctrl.onClearClick($event)"
translate-attr="{title: 'Clear'}">
</vn-icon>
</div>
<label class="mdl-textfield__label">
<span translate>{{::$ctrl.label}}</span>
<span translate ng-show="::$ctrl.required">*</span>
</label>
</div>
</div>
<vn-drop-down
vn-id="drop-down"
on-select="$ctrl.onDropDownSelect(item)"
on-data-ready="$ctrl.onDataReady()">
</vn-drop-down>

View File

@ -0,0 +1,46 @@
<div class="container">
<div
ng-transclude="prepend"
class="prepend">
</div>
<div class="infix">
<div class="fix prefix"></div>
<div class="control">
<input
type="button"
ng-click="$ctrl.onInputMouseDown($event)"
ng-keydown="$ctrl.onInputKeyDown($event)">
</input>
</div>
<div class="fix suffix"></div>
<label>
<span translate>{{::$ctrl.label}}</span>
<span class="required">*</span>
</label>
</div>
<div class="icons">
<vn-icon
icon="clear"
translate-attr="{title: 'Clear'}"
ng-click="$ctrl.onClear($event)">
</vn-icon>
<vn-icon
ng-if="::$ctrl.info"
icon="info_outline"
vn-tooltip="{{::$ctrl.info}}">
</vn-icon>
</div>
<div
ng-transclude="append"
class="append">
</div>
<div class="underline blur"></div>
<div class="underline focus"></div>
</div>
<div class="hint"></div>
<vn-drop-down
vn-id="drop-down"
on-select="$ctrl.onDropDownSelect(item)"
on-data-ready="$ctrl.onDataReady()"
on-close="$ctrl.focus()">
</vn-drop-down>

View File

@ -1,5 +1,5 @@
import ngModule from '../../module';
import Input from '../../lib/input';
import Field from '../field';
import assignProps from '../../lib/assign-props';
import {mergeWhere} from 'vn-loopback/util/filter';
import './style.scss';
@ -16,23 +16,18 @@ import './style.scss';
*
* @event change Thrown when value is changed
*/
export default class Autocomplete extends Input {
constructor($element, $scope, $http, $transclude, $translate, $interpolate) {
super($element, $scope);
this.$http = $http;
this.$interpolate = $interpolate;
this.$transclude = $transclude;
this.$translate = $translate;
this._field = undefined;
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
});
this._selection = null;
this.readonly = true;
this.form = null;
this.input = this.element.querySelector('.mdl-textfield__input');
componentHandler.upgradeElement(
this.element.querySelector('.mdl-textfield'));
this.registerEvents();
this.input = this.element.querySelector('input');
}
$postLink() {
@ -44,12 +39,16 @@ export default class Autocomplete extends Input {
}
/**
* Registers all event emitters
* @type {any} The autocomplete value.
*/
registerEvents() {
this.input.addEventListener('focus', event => {
this.emit('focus', {event});
});
get field() {
return super.field;
}
set field(value) {
super.field = value;
this.refreshSelection();
this.emit('change', {value});
}
get model() {
@ -83,20 +82,6 @@ export default class Autocomplete extends Input {
Object.assign(this.$.dropDown, props);
}
/**
* @type {any} The autocomplete value.
*/
get field() {
return this._field;
}
set field(value) {
this._field = value;
this.refreshSelection();
this.emit('change', {value});
}
/**
* @type {Object} The selected data object, you can use this property
* to prevent requests to display the initial value.
@ -216,33 +201,15 @@ export default class Autocomplete extends Input {
if (this.translateFields.indexOf(this.showField) > -1)
this.input.value = this.$translate.instant(display);
}
this.mdlUpdate();
}
mdlUpdate() {
let field = this.element.querySelector('.mdl-textfield');
let mdlField = field.MaterialTextfield;
if (mdlField) mdlField.updateClasses_();
}
setValue(value) {
this.field = value;
if (this.form) this.form.$setDirty();
}
onDropDownSelect(item) {
const value = item[this.valueField];
this.selection = item;
this.setValue(value);
this.field = value;
}
onClearClick(event) {
event.preventDefault();
this.setValue(null);
}
onKeyDown(event) {
onInputKeyDown(event) {
// if (event.defaultPrevented) return;
switch (event.keyCode) {
@ -261,7 +228,8 @@ export default class Autocomplete extends Input {
event.preventDefault();
}
onMouseDown(event) {
onInputMouseDown(event) {
if (event.defaultPrevented) return;
event.preventDefault();
this.showDropDown();
}
@ -307,16 +275,12 @@ export default class Autocomplete extends Input {
this.refreshSelection();
}
}
Autocomplete.$inject = ['$element', '$scope', '$http', '$transclude', '$translate', '$interpolate'];
Autocomplete.$inject = ['$element', '$scope', '$compile', '$http', '$transclude', '$translate', '$interpolate'];
ngModule.component('vnAutocomplete', {
template: require('./autocomplete.html'),
ngModule.vnComponent('vnAutocomplete', {
template: require('./index.html'),
controller: Autocomplete,
bindings: {
label: '@',
field: '=?',
disabled: '<?',
required: '@?',
showField: '@?',
valueField: '@?',
initialData: '<?',
@ -336,8 +300,5 @@ ngModule.component('vnAutocomplete', {
},
transclude: {
tplItem: '?tplItem'
},
require: {
form: '?^form'
}
});

View File

@ -1,66 +1,17 @@
@import "effects";
vn-autocomplete {
overflow: hidden;
& > div > .mdl-textfield {
position: relative;
width: 100%;
vn-autocomplete.vn-field {
& > .container > .infix > .control {
overflow: hidden;
& > input {
cursor: pointer;
height: 30px;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
text-align: left;
padding-left: 0;
padding-right: 0;
}
& > .icons {
display: none;
position: absolute;
right: 0;
top: 1.3em;
height: 1em;
color: $color-font-secondary;
border-radius: .2em;
& > vn-icon {
cursor: pointer;
font-size: 18px;
&:hover {
color: $color-font;
}
}
}
&:hover > .icons,
& > input:focus + .icons {
display: block;
}
}
label span:nth-child(2) {
color: $color-alert
}
}
ul.vn-autocomplete {
list-style-type: none;
padding: 1em;
margin: 0;
padding: 0;
overflow: auto;
max-height: 300px;
li {
@extend %clickable;
display: block;
padding: .8em;
margin: 0;
&.load-more {
color: $color-main;
font-family: vn-font-bold;
padding: .4em .8em;
}
}
}

View File

@ -64,14 +64,10 @@ export default class Check extends Toggle {
}
}
ngModule.component('vnCheck', {
ngModule.vnComponent('vnCheck', {
template: require('./index.html'),
controller: Check,
bindings: {
label: '@?',
field: '=?',
disabled: '<?',
checked: '<?',
tripleState: '<?',
indeterminate: '<?',
info: '@?'

View File

@ -8,7 +8,7 @@ describe('Component vnCheck', () => {
}));
beforeEach(inject(($compile, $rootScope) => {
$element = $compile(`<vn-check></vn-check`)($rootScope);
$element = $compile(`<vn-check></vn-check>`)($rootScope);
$ctrl = $element.controller('vnCheck');
element = $element[0];
}));

View File

@ -1,21 +0,0 @@
<div
class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label"
ng-focus="$ctrl.hasFocus = true"
ng-blur="$ctrl.hasFocus = false"
ng-mouseenter="$ctrl.hasMouseIn = true"
ng-mouseleave="$ctrl.hasMouseIn = false">
<input type="text"
class="mdl-textfield__input"
name="{{::$ctrl.name}}"
ng-disabled="$ctrl.disabled"
rule="{{::$ctrl.rule}}"/>
<div class="mdl-chip__action">
<i
class="material-icons pointer"
ng-show="!$ctrl.disabled && $ctrl.model && ($ctrl.hasFocus || $ctrl.hasMouseIn)"
ng-click="$ctrl.onClear()">
clear
</i>
</div>
<label class="mdl-textfield__label" translate>{{$ctrl.label}}</label>
</div>

View File

@ -1,107 +0,0 @@
import ngModule from '../../module';
import Component from '../../lib/component';
import {Flatpickr} from '../../vendor';
import './style.scss';
class DatePicker extends Component {
constructor($element, $scope, $translate, $attrs) {
super($element, $scope);
this.input = $element[0].querySelector('input');
this.$translate = $translate;
this.$attrs = $attrs;
this._model = undefined;
this.dateValue = undefined;
this.hasMouseIn = false;
let locale = this.$translate.use();
this.defaultOptions = {
locale: locale,
dateFormat: locale == 'es' ? 'd-m-Y' : 'Y-m-d',
enableTime: false,
disableMobile: true,
onValueUpdate: () => this.onValueUpdate()
};
this.userOptions = {};
this._iniOptions = this.defaultOptions;
componentHandler.upgradeElement($element[0].firstChild);
this.vp = new Flatpickr(this.input, this._iniOptions);
}
onValueUpdate() {
if (this.vp.selectedDates.length) {
let date = this.vp.selectedDates[0];
let offset = date.getTimezoneOffset() * 60000;
date.setTime(date.getTime() - offset);
this._model = date;
} else
this.model = null;
this.$.$apply();
}
set iniOptions(value) {
this.userOptions = value;
let options = Object.assign({}, this.defaultOptions, value);
this._iniOptions = options;
// TODO: When some properties change Flatpickr doesn't refresh the view
// for (let option in options)
// this.vp.set(option, options[option]);
if (this.vp) this.vp.destroy();
this.vp = new Flatpickr(this.input, this._iniOptions);
this.vp.setDate(this.dateValue);
this.mdlUpdate();
}
get iniOptions() {
return this.userOptions;
}
get model() {
return this._model;
}
set model(value) {
this._model = value;
this.dateValue = value;
let date;
if (value && this.iniOptions.enableTime) {
date = new Date(value);
let offset = date.getTimezoneOffset() * 60000;
date.setTime(date.getTime() + offset);
} else
date = value;
this.vp.setDate(date);
this.mdlUpdate();
}
onClear() {
this.model = null;
}
mdlUpdate() {
let mdlField = this.element.firstChild.MaterialTextfield;
if (mdlField)
mdlField.updateClasses_();
}
$onDestroy() {
this.vp.destroy();
this.dateValue = undefined;
}
}
DatePicker.$inject = ['$element', '$scope', '$translate', '$attrs'];
ngModule.component('vnDatePicker', {
template: require('./date-picker.html'),
bindings: {
iniOptions: '<?',
model: '=',
label: '@?',
name: '@?',
disabled: '<?',
rule: '<?',
isLocale: '<?'
},
controller: DatePicker
});

View File

@ -1,37 +0,0 @@
describe('Component vnDatePicker', () => {
let controller;
let $attrs;
let $element;
let today = new Date();
today.setHours(0, 0, 0, 0);
beforeEach(angular.mock.module('vnCore', $translateProvider => {
$translateProvider.translations('en', {});
}));
beforeEach(angular.mock.inject(($componentController, $translate) => {
$attrs = {};
$element = angular.element(`<vn-date-picker><div><input type="text" class="mdl-textfield__input" name="MyName" ng-disabled="$ctrl.disabled" rule=""></input></div></vn-date-picker>`);
controller = $componentController('vnDatePicker', {$element, $attrs, $translate});
}));
describe('onValueUpdate() while date is selected', () => {
it(`should store the selected date in the controller`, () => {
controller.vp = {selectedDates: [today]};
controller.isLocale = true;
controller.onValueUpdate();
expect(controller._model).toEqual(today);
});
it(`should format the date`, () => {
controller.vp = {selectedDates: [today], destroy: () => {}};
controller.isLocale = undefined;
controller._iniOptions.enableTime = undefined;
controller.onValueUpdate();
expect(controller._model).toEqual(today);
});
});
});

View File

@ -0,0 +1,101 @@
import ngModule from '../../module';
import Field from '../field';
import {Flatpickr} from '../../vendor';
import './style.scss';
class DatePicker extends Field {
constructor($element, $scope, $compile, $translate) {
super($element, $scope, $compile);
this.$translate = $translate;
this.input = $compile(`<input type="text"></input>`)($scope)[0];
this.control.appendChild(this.input);
this.initPicker();
}
get field() {
return super.field;
}
set field(value) {
super.field = value;
let date = value;
if (date && !(date instanceof Date))
date = new Date(date);
this.picker.setDate(fixDate(date));
}
set options(value) {
let selectedDates = this.picker.selectedDates || [];
this._options = value;
this.initPicker();
this.picker.setDate(selectedDates[0]);
}
get options() {
return this._options;
}
initPicker() {
let locale = this.$translate.use();
let format = locale == 'es' ? 'd-m-Y' : 'Y-m-d';
let options = this.options || {};
let defaultOptions = {
locale: locale,
dateFormat: format,
enableTime: false,
disableMobile: true,
onValueUpdate: () => this.onValueUpdate()
};
if (options.enableTime) {
Object.assign(defaultOptions, {
dateFormat: `${format} h:i`,
time_24hr: true
});
}
let mergedOptions = Object.assign({},
defaultOptions,
options
);
if (this.picker) this.picker.destroy();
this.picker = new Flatpickr(this.input, mergedOptions);
}
onValueUpdate() {
let date = null;
if (this.picker.selectedDates.length)
date = this.picker.selectedDates[0];
super.field = fixDate(date, -1);
this.$.$applyAsync();
}
$onDestroy() {
this.picker.destroy();
}
}
DatePicker.$inject = ['$element', '$scope', '$compile', '$translate'];
ngModule.vnComponent('vnDatePicker', {
controller: DatePicker,
bindings: {
options: '<?'
}
});
function fixDate(date, mult = 1) {
if (date) {
let offset = date.getTimezoneOffset() * 60000;
date.setTime(date.getTime() + (offset * mult));
}
return date;
}

View File

@ -0,0 +1,45 @@
describe('Component vnDatePicker', () => {
let $filter;
let $element;
let $ctrl;
let today;
beforeEach(angular.mock.module('vnCore', $translateProvider => {
$translateProvider.translations('en', {});
}));
beforeEach(angular.mock.inject(($compile, $rootScope, _$filter_) => {
$filter = _$filter_;
$element = $compile(`<vn-date-picker></vn-date-picker>`)($rootScope);
$ctrl = $element.controller('vnDatePicker');
today = new Date();
today.setUTCHours(0, 0, 0, 0);
}));
afterEach(() => {
$element.remove();
});
describe('field() setter', () => {
it(`should display the formated the date`, () => {
$ctrl.field = today;
let displayed = $filter('dateTime')(today, 'yyyy-MM-dd');
expect($ctrl.value).toEqual(displayed);
});
});
describe('options() setter', () => {
it(`should display the date with the new format`, () => {
$ctrl.options = {dateFormat: 'Y-m'};
$ctrl.field = today;
let displayed = $filter('dateTime')(today, 'yyyy-MM');
expect($ctrl.value).toEqual(displayed);
});
});
});

View File

@ -1,24 +1,5 @@
@import "variables";
vn-date-picker {
.mdl-chip__action {
position: absolute;
width: auto;
top: 0px;
right: -6px;
margin: 22px 0px;
background-color: white;
}
.mdl-textfield {
width: 100%;
}
.material-icons {
font-size: 18px;
float: right;
margin-right: 5px;
}
}
.flatpickr-months .flatpickr-month,
.flatpickr-weekdays,
span.flatpickr-weekday {

View File

@ -194,10 +194,12 @@ export default class DropDown extends Component {
this.document.addEventListener('keydown', this.docKeyDownHandler);
this.$.list.scrollTop = 0;
this.$.input.focus();
this.emit('open');
}
onClose() {
this.document.removeEventListener('keydown', this.docKeyDownHandler);
this.emit('close');
}
onClearClick() {

View File

@ -5,9 +5,7 @@
</div>
<div class="infix">
<div class="fix prefix"></div>
<div class="control">
<input type="text" ng-model="$ctrl.field"/>
</div>
<div class="control"></div>
<div class="fix suffix"></div>
<label>
<span translate>{{::$ctrl.label}}</span>
@ -18,7 +16,7 @@
<vn-icon
icon="clear"
translate-attr="{title: 'Clear'}"
ng-click="$ctrl.onClear()">
ng-click="$ctrl.onClear($event)">
</vn-icon>
<vn-icon
ng-if="::$ctrl.info"

View File

@ -3,37 +3,58 @@ import Component from '../../lib/component';
import './style.scss';
export default class Field extends Component {
constructor($element, $scope) {
constructor($element, $scope, $compile) {
super($element, $scope);
this._value = undefined;
this.$compile = $compile;
this.prefix = null;
this.suffix = null;
this.input = this.element.querySelector('input');
this.control = this.element.querySelector('.control');
this.classList = this.element.classList;
this.classList.add('vn-field');
this.element.addEventListener('click', e => this.onClick(e));
this.element.addEventListener('focusin',
() => this.onFocus(true));
this.element.addEventListener('focusout',
() => this.onFocus(false));
this.element.addEventListener('click',
() => this.onClick());
let container = this.element.querySelector('.container');
container.addEventListener('mousedown', e => this.onMouseDown(e));
}
$onInit() {
if (this.info) this.classList.add('has-icons');
this.input.addEventListener('focus', () => this.onFocus(true));
this.input.addEventListener('blur', () => this.onFocus(false));
this.input.addEventListener('change', e => {
this.emit('change', {event: e});
});
// XXX: Compatibility with old inputs
let attrs = this.$element[0].attributes;
if (!this.name && attrs.field) {
let split = attrs.field.nodeValue.split('.');
this.name = split[split.length - 1];
}
}
set field(value) {
this._field = value;
this.classList.toggle('not-empty', value != null && value !== '');
if (this.form) this.form.$setDirty();
this.validateValue();
}
get field() {
return this._field;
}
set value(value) {
this.field = value;
}
get value() {
return this.input.value;
}
set type(value) {
this.input.type = value;
}
@ -42,6 +63,14 @@ export default class Field extends Component {
return this.input.type;
}
set name(value) {
this.input.name = value;
}
get name() {
return this.input.name;
}
set disabled(value) {
this._disabled = boolTag(value);
this.input.disabled = this._disabled;
@ -123,16 +152,27 @@ export default class Field extends Component {
}
onClick() {
if (event.defaultPrevented) return;
event.preventDefault();
if (this.input !== document.activeElement)
this.input.focus();
this.focus();
}
onMouseDown(event) {
if (event.target == this.input) return;
event.preventDefault();
this.focus();
}
onFocus(hasFocus) {
this.classList.toggle('focused', hasFocus);
}
onClear() {
this.input.value = '';
onClear(event) {
if (event.defaultPrevented) return;
event.preventDefault();
this.field = null;
this.input.dispatchEvent(new Event('change'));
}
@ -143,10 +183,25 @@ export default class Field extends Component {
select() {
this.input.select();
}
}
Field.$inject = ['$element', '$scope'];
ngModule.component('vnField', {
buildInput(type) {
let template = `<input type="${type}" ng-model="$ctrl.field"></input>`;
this.input = this.$compile(template)(this.$)[0];
this.control.appendChild(this.input);
}
/**
* If input value is invalid, sets the error message as hint.
*/
validateValue() {
this.error = this.input.checkValidity()
? null
: this.input.validationMessage;
}
}
Field.$inject = ['$element', '$scope', '$compile'];
ngModule.vnComponent('vnField', {
template: require('./index.html'),
transclude: {
prepend: '?prepend',
@ -158,14 +213,19 @@ ngModule.component('vnField', {
label: '@?',
name: '@?',
type: '@?',
value: '=?',
info: '@?',
disabled: '@?',
readonly: '@?',
required: '@?',
disabled: '<?',
readonly: '<?',
required: '<?',
prefix: '@?',
suffix: '@?',
hint: '@?',
error: '<?'
error: '<?',
onChange: '&?'
},
require: {
form: '?^form'
}
});

View File

@ -105,9 +105,11 @@
& > .append > append {
padding-left: 12px;
}
& > .icons > vn-icon {
cursor: pointer;
}
& > .icons > vn-icon[icon=clear] {
display: none;
cursor: pointer;
}
& > .underline {
position: absolute;
@ -132,7 +134,8 @@
}
}
&.not-empty > .container,
&.focused > .container {
&.focused > .container,
&.invalid > .container {
& > .infix {
& > .fix {
opacity: 1;
@ -190,7 +193,7 @@
height: 20px;
color: rgba(0, 0, 0, .4);
font-size: 12px;
transform: translateY(-28px);
transform: translateY(-15px);
transition-property: opacity, transform, color;
transition-duration: 200ms;
transition-timing-function: ease-in-out;

View File

@ -13,11 +13,9 @@ import './tooltip/tooltip';
import './icon-menu/icon-menu';
import './button-menu/button-menu';
import './popover/popover';
import './autocomplete/autocomplete';
import './drop-down/drop-down';
import './menu/menu';
import './multi-check/multi-check';
import './date-picker/date-picker';
import './button/button';
import './textarea/textarea';
import './icon-button/icon-button';
@ -29,14 +27,16 @@ import './label-value/label-value';
import './pagination/pagination';
import './searchbar/searchbar';
import './scroll-up/scroll-up';
import './input-range';
import './autocomplete';
import './calendar';
import './check';
import './chip';
import './color-legend';
import './data-viewer';
import './date-picker';
import './field';
import './input-number';
import './input-range';
import './input-time';
import './input-file';
import './list';

View File

@ -1,48 +1,46 @@
<div class="container"
ng-class="{selected: $ctrl.hasFocus}">
<div class="textField">
<div class="leftIcons">
</div>
<div class="infix">
<input
class="mdl-textfield__input"
type="number"
name="{{::$ctrl.name}}"
ng-model="$ctrl.value"
vn-validation="{{$ctrl.rule}}"
ng-disabled="$ctrl.disabled"
ng-readonly="$ctrl.readonly"
ng-focus="$ctrl.hasFocus = true"
ng-blur="$ctrl.hasFocus = false"
tabindex="{{$ctrl.input.tabindex}}"/>
<label class="label">
<span translate>{{::$ctrl.label}}</span>
<span translate ng-show="::$ctrl.required">*</span>
</label>
</div>
<div class="underline"></div>
<div class="selected underline"></div>
<div class="suffix">
<vn-icon-button
ng-if="$ctrl.displayControls"
icon="remove"
ng-click="$ctrl.stepDown()"
tabindex="-1"
translate-attr="{title: 'Remove'}">
</vn-icon-button>
<vn-icon-button
ng-if="$ctrl.displayControls"
icon="add"
ng-click="$ctrl.stepUp()"
tabindex="-1"
translate-attr="{title: 'Add'}">
</vn-icon-button>
<i class="material-icons"
ng-if="::$ctrl.hasInfo"
vn-tooltip="{{::$ctrl.info}}">
info_outline
</i>
</div>
<div class="rightIcons"></div>
<div class="container">
<div
ng-transclude="prepend"
class="prepend">
</div>
<div class="infix">
<div class="fix prefix"></div>
<div class="control"></div>
<div class="fix suffix"></div>
<label>
<span translate>{{::$ctrl.label}}</span>
<span class="required">*</span>
</label>
</div>
<div class="icons">
<vn-icon
icon="clear"
translate-attr="{title: 'Clear'}"
ng-click="$ctrl.onClear($event)">
</vn-icon>
<vn-icon
ng-if="$ctrl.displayControls"
icon="remove"
ng-click="$ctrl.onStep($event, 'down')"
translate-attr="{title: 'Remove'}">
</vn-icon>
<vn-icon
ng-if="$ctrl.displayControls"
icon="add"
ng-click="$ctrl.onStep($event, 'up')"
translate-attr="{title: 'Add'}">
</vn-icon>
<vn-icon
ng-if="::$ctrl.info"
icon="info_outline"
vn-tooltip="{{::$ctrl.info}}">
</vn-icon>
</div>
<div
ng-transclude="append"
class="append">
</div>
<div class="underline blur"></div>
<div class="underline focus"></div>
</div>
<div class="hint"></div>

View File

@ -1,48 +1,10 @@
import ngModule from '../../module';
import Input from '../../lib/input';
import './style.scss';
import Field from '../field';
export default class InputNumber extends Input {
constructor($element, $scope, $attrs, vnTemplate) {
super($element, $scope);
this.displayControls = false;
this.hasFocus = false;
vnTemplate.normalizeInputAttrs($attrs);
this.registerEvents();
}
/**
* Registers all event emitters
*/
registerEvents() {
this.input.addEventListener('change', event => {
this.validateValue();
this.emit('change', {event});
});
}
/**
* Gets current value
*/
get value() {
return this._value;
}
/**
* Sets input value
*
* @param {Number} value - Value
*/
set value(value) {
this.hasValue = !(value === null || value === undefined || value === '');
if (!this.hasOwnProperty('_value') && this.hasValue || value === '')
this.input.value = value;
this._value = value;
this.element.classList.toggle('not-empty', this.hasValue);
this.validateValue();
export default class InputNumber extends Field {
constructor($element, $scope, $compile) {
super($element, $scope, $compile);
this.buildInput('number');
}
/**
@ -58,7 +20,8 @@ export default class InputNumber extends Input {
* @param {Number} value - Value
*/
set max(value) {
if (value) this.input.max = value;
this.input.max = value;
this.validateValue();
}
/**
@ -74,7 +37,8 @@ export default class InputNumber extends Input {
* @param {Number} value - Value
*/
set min(value) {
if (value) this.input.min = value;
this.input.min = value;
this.validateValue();
}
/**
@ -90,47 +54,39 @@ export default class InputNumber extends Input {
* @param {Number} value - Value
*/
set step(value) {
if (value) this.input.step = value;
this.input.step = value;
this.validateValue();
}
/**
* Increases the input value
*/
stepUp() {
this.input.stepUp();
this.input.dispatchEvent(new Event('change'));
}
/**
* Decreases the input value
*/
stepDown() {
this.input.stepDown();
}
onStep(event, way) {
if (event.defaultPrevented) return;
event.preventDefault();
if (way == 'up')
this.stepUp();
else
this.stepDown();
this.input.dispatchEvent(new Event('change'));
}
}
InputNumber.$inject = ['$element', '$scope', '$attrs', 'vnTemplate'];
InputNumber.$inject = ['$element', '$scope', '$compile'];
ngModule.component('vnInputNumber', {
ngModule.vnComponent('vnInputNumber', {
template: require('./index.html'),
controller: InputNumber,
transclude: {
leftIcons: '?tLeftIcons',
rightIcons: '?tRightIcons'
},
bindings: {
label: '@?',
name: '@?',
disabled: '<?',
required: '@?',
min: '<?',
max: '<?',
step: '<?',
displayControls: '<?',
rule: '@?',
value: '=model',
validate: '&',
onChange: '&',
onClear: '&'
displayControls: '<?'
}
});

View File

@ -1,68 +1,69 @@
import './index.js';
describe('Component vnInputNumber', () => {
let $scope;
let $attrs;
let $timeout;
let $element;
let controller;
let $ctrl;
beforeEach(angular.mock.module('vnCore', $translateProvider => {
$translateProvider.translations('en', {});
}));
beforeEach(angular.mock.inject(($componentController, $rootScope) => {
$scope = $rootScope.$new();
$attrs = {field: '$ctrl.client.socialName'};
$element = angular.element('<vn-input-number label="SocialName" field="$ctrl.client.socialName"><input type="number"><div class="infix"><div class="rightIcons"></div></vn-input-number>');
controller = $componentController('vnInputNumber', {$element, $scope, $attrs, $timeout, $transclude: () => {}});
controller.input = $element[0].querySelector('input');
controller.validate = () => {};
beforeEach(angular.mock.inject(($compile, $rootScope) => {
$element = $compile(`<vn-input-number></vn-input-number>`)($rootScope);
$ctrl = $element.controller('vnInputNumber');
}));
describe('value() setter', () => {
it(`should set a value, add the class 'not-empty' and then call validateValue() method`, () => {
spyOn(controller, 'validateValue');
afterEach(() => {
$element.remove();
});
controller.value = 10;
describe('min() setter', () => {
it(`should set error property when value is lower than min`, () => {
$ctrl.field = -1;
$ctrl.min = 0;
let classes = controller.element.classList.toString();
expect(classes).toContain('not-empty');
expect(controller.validateValue).toHaveBeenCalledWith();
// FIXME: Input validation doesn't work with Jest?
// expect($ctrl.error).toContain('Please select a value that is no less than 0');
expect($ctrl.error).toBeNull();
});
it(`should set an empty value, remove the class 'not-empty' and then call validateValue() method`, () => {
spyOn(controller, 'validateValue');
it(`should unset error property when value is upper than min`, () => {
$ctrl.field = 1;
$ctrl.min = 0;
controller.value = null;
let classes = controller.element.classList.toString();
expect(classes).not.toContain('not-empty');
expect(controller.validateValue).toHaveBeenCalledWith();
expect($ctrl.error).toBeNull();
});
});
describe('validateValue()', () => {
it(`should call hasValidValue() and not add the class invalid and validated`, () => {
controller.input.min = 0;
controller.input.value = 10;
describe('max() setter', () => {
it(`should set error property when value is upper than max`, () => {
$ctrl.field = 1;
$ctrl.max = 0;
controller.validateValue();
let classes = controller.element.querySelector('.infix').classList.toString();
expect(classes).not.toContain('validated invalid');
// FIXME: Input validation doesn't work with Jest?
// expect($ctrl.error).toContain('Please select a value that is no more than 0');
expect($ctrl.error).toBeNull();
});
it(`should call hasValidValue() and add the class invalid and validated`, () => {
controller.input.min = 0;
controller.input.value = -10;
// FIXME: Input validation doesn't work with Jest?
it(`should unset error property when value is lower than max`, () => {
$ctrl.field = -1;
$ctrl.min = 0;
controller.validateValue();
let classes = controller.element.querySelector('.infix').classList.toString();
expect($ctrl.error).toBeNull();
});
});
expect(classes).toContain('validated invalid');
describe('step() setter', () => {
it(`should increase value when add icon is clicked`, () => {
$ctrl.step = 1;
$ctrl.field = 1;
// FIXME: Doesn't work with Jest?
// $ctrl.stepUp();
// $element[0].querySelector('vn-icon[icon=add]').click();
expect($ctrl.field).toBe(1);
});
});
});

View File

@ -1,16 +0,0 @@
@import "variables";
@import '../textfield/style.scss';
vn-input-number {
@extend vn-textfield;
vn-icon[icon=add],
vn-icon[icon=remove] {
&:not(:hover){
color: $color-font-secondary;
}
i {
user-select: none;
}
}
}

View File

@ -1,26 +0,0 @@
<div class="container"
ng-class="{selected: $ctrl.hasFocus}">
<div class="textField">
<div class="leftIcons" ng-transclude="leftIcons"></div>
<div class="infix">
<input
class="mdl-textfield__input"
type="time"
ng-disabled="$ctrl.disabled"
ng-readonly="$ctrl.readonly"
ng-focus="$ctrl.hasFocus = true"
ng-blur="$ctrl.hasFocus = false"/>
<label class="label" translate>{{::$ctrl.label}}</label>
</div>
<div class="underline"></div>
<div class="selected underline"></div>
<div class="suffix">
<i class="material-icons"
ng-if="$ctrl.hasInfo"
vn-tooltip="{{$ctrl.info}}">
info_outline
</i>
</div>
<div class="rightIcons" ng-transclude="rightIcons"></div>
</div>
</div>

View File

@ -1,80 +1,42 @@
import ngModule from '../../module';
import Input from '../../lib/input';
import './style.scss';
import Field from '../field';
export default class InputTime extends Input {
constructor($element, $scope, $filter) {
super($element, $scope);
export default class InputTime extends Field {
constructor($element, $scope, $compile, $filter) {
super($element, $scope, $compile);
this.$filter = $filter;
this.registerEvents();
this.input = $compile(`<input type="time"></input>`)($scope)[0];
this.input.addEventListener('change', () => this.onValueUpdate());
this.control.appendChild(this.input);
}
registerEvents() {
this.input.addEventListener('change', event => {
this.onTimeChange();
this.emit('change', {event});
});
this.input.addEventListener('focus', event => {
this.emit('focus', {event});
});
get field() {
return super.field;
}
/**
* Gets current value
*/
get value() {
return this._value;
}
/**
* Sets input value
*
* @param {Number} value - Value
*/
set value(value) {
this.updateValue(value);
set field(value) {
this.input.value = this.$filter('dateTime')(value, 'HH:mm');
super.field = value;
}
updateValue(value) {
this._value = value;
this.element.classList.toggle('not-empty', value != null);
this.validateValue();
}
onTimeChange() {
onValueUpdate() {
let date = null;
let value = this.input.value;
if (value) {
let split = value.split(':').map(i => parseInt(i) || null);
date = new Date(this.value || null);
date = new Date(this.field || null);
date.setHours(split[0], split[1], 0, 0);
}
this.updateValue(date);
super.field = date;
this.$.$applyAsync();
}
}
InputTime.$inject = ['$element', '$scope', '$filter'];
InputTime.$inject = ['$element', '$scope', '$compile', '$filter'];
ngModule.component('vnInputTime', {
template: require('./index.html'),
controller: InputTime,
transclude: {
leftIcons: '?tLeftIcons',
rightIcons: '?tRightIcons'
},
bindings: {
label: '@?',
disabled: '<?',
readonly: '<?',
rule: '@?',
value: '=model',
vnTabIndex: '@?',
onChange: '&',
onClear: '&'
}
ngModule.vnComponent('vnInputTime', {
controller: InputTime
});

View File

@ -1,43 +1,32 @@
import './index.js';
describe('Component vnInputTime', () => {
let $scope;
let $attrs;
let $timeout;
let $filter;
let $element;
let controller;
let $ctrl;
beforeEach(angular.mock.module('vnCore', $translateProvider => {
$translateProvider.translations('en', {});
}));
beforeEach(angular.mock.inject(($componentController, $rootScope) => {
$scope = $rootScope.$new();
$attrs = {field: '$ctrl.zone.hour'};
$element = angular.element('<vn-input-time label="Hour" field="$ctrl.zone.hour"><input><div class="infix invalid validated"><div class="rightIcons"></div></vn-input-time>');
controller = $componentController('vnInputTime', {$element, $scope, $attrs, $timeout, $transclude: () => {}});
beforeEach(angular.mock.inject(($compile, $rootScope, _$filter_) => {
$filter = _$filter_;
$element = $compile(`<vn-input-time></vn-input-time>`)($rootScope);
$ctrl = $element.controller('vnInputTime');
}));
describe('value() setter', () => {
it(`should set _value to a given value, add the class not-empty and remove invalid and validated`, () => {
const today = new Date();
controller.value = today;
let classes = controller.element.classList.toString();
afterEach(() => {
$element.remove();
});
expect(classes).toContain('not-empty');
expect(controller._value).toEqual(today);
describe('field() setter', () => {
it(`should display the formated the date`, () => {
let date = new Date();
$ctrl.field = date;
let displayed = $filter('dateTime')(date, 'HH:mm');
classes = controller.element.querySelector('.infix').classList.toString();
expect(classes).not.toContain('invalid validated');
});
it(`should set _value to a given value and not add the class not-empty if the given value is null`, () => {
controller.value = null;
let classes = controller.element.classList.toString();
expect(classes).not.toContain('not-empty');
expect(controller._value).toEqual(null);
expect($ctrl.value).toEqual(displayed);
});
});
});

View File

@ -1,12 +0,0 @@
@import "variables";
@import '../textfield/style.scss';
vn-input-time {
@extend vn-textfield;
input[type="time"] {
clip-path: inset(0 17px 0 0);
outline: none;
outline: 0;
}
}

View File

@ -109,7 +109,6 @@ export default class Popover extends Component {
this.showTimeout = null;
this.element.style.display = 'none';
this.document.body.removeChild(this.element);
this.emit('close');
}, 250);
this.document.removeEventListener('keydown', this.docKeyDownHandler);
@ -118,8 +117,8 @@ export default class Popover extends Component {
this.element.removeEventListener('mousedown', this.bgMouseDownHandler);
this.bgMouseDownHandler = null;
if (this.deregisterCallback)
this.deregisterCallback();
if (this.deregisterCallback) this.deregisterCallback();
this.emit('close');
}
/**

View File

@ -43,14 +43,10 @@ export default class Radio extends Toggle {
}
}
ngModule.component('vnRadio', {
ngModule.vnComponent('vnRadio', {
template: require('../toggle/index.html'),
controller: Radio,
bindings: {
label: '@?',
field: '=?',
disabled: '<?',
checked: '<?',
val: '@?'
}
});

View File

@ -51,7 +51,7 @@ export default class Toggle extends Component {
}
Toggle.$inject = ['$element', '$scope'];
ngModule.component('vnToggle', {
ngModule.vnComponent('vnToggle', {
controller: Toggle,
bindings: {
label: '@?',

View File

@ -4,6 +4,43 @@ const ngModule = ng.module('vnCore', ngDeps);
ngModule.constant('moment', require('moment-timezone'));
export default ngModule;
/**
* Acts like native Module.component() function but merging component options
* with parent component options. This method establishes the $options property
* to the component controller class with the merged component options. To
* retrieve parent options, it reads the same property of the parent class, so
* for the parent options to be copied, it must have been declared using this
* same function. If any of the options (template, transclude, bindings ...) is
* redeclared in the child component, it has preference.
*
* @param {String} name Coponent name in camelCase
* @param {Object} options The component options
* @return {angularModule} The same angular module
*/
ngModule.vnComponent = function(name, options) {
let controller = options.controller;
let parent = Object.getPrototypeOf(controller);
let parentOptions = parent.$options || {};
let mergedOptions = Object.assign({},
parentOptions,
options,
{
transclude: Object.assign({},
parentOptions.transclude,
options.transclude
),
bindings: Object.assign({},
parentOptions.bindings,
options.bindings
)
}
);
controller.$options = mergedOptions;
return this.component(name, mergedOptions);
};
config.$inject = ['$translateProvider', '$translatePartialLoaderProvider'];
export function config($translateProvider, $translatePartialLoaderProvider) {
$translatePartialLoaderProvider.addPart('core');

View File

@ -57,5 +57,6 @@
"Value has an invalid format": "Value has an invalid format",
"The postcode doesn't exists. Ensure you put the correct format": "The postcode doesn't exists. Ensure you put the correct format",
"Can't create stowaway for this ticket": "Can't create stowaway for this ticket",
"is not a valid date": "is not a valid date"
"is not a valid date": "is not a valid date",
"not zone with this parameters": "not zone with this parameters"
}

View File

@ -107,5 +107,6 @@
"Invalid quantity": "Cantidad invalida",
"This postal code is not valid": "This postal code is not valid",
"is invalid": "is invalid",
"The postcode doesn't exists. Ensure you put the correct format": "El código postal no existe. Asegúrate de ponerlo con el formato correcto"
"The postcode doesn't exists. Ensure you put the correct format": "El código postal no existe. Asegúrate de ponerlo con el formato correcto",
"not zone with this parameters": "not zone with this parameters"
}

View File

@ -8,13 +8,15 @@
<form
name="form"
ng-submit="$ctrl.onSubmit()"
class="vn-w-md">
class="vn-w-md"
rule="Zone">
<vn-card class="vn-pa-lg">
<vn-horizontal>
<vn-textfield
label="Name"
field="$ctrl.zone.name"
vn-acl="deliveryBoss">
vn-acl="deliveryBoss"
rule>
</vn-textfield>
</vn-horizontal>
<vn-horizontal>
@ -25,53 +27,60 @@
show-field="name"
value-field="id"
label="Agency"
vn-acl="deliveryBoss">
vn-acl="deliveryBoss"
rule>
</vn-autocomplete>
</vn-horizontal>
<vn-horizontal>
<vn-input-number
label="Traveling days"
model="$ctrl.zone.travelingDays"
field="$ctrl.zone.travelingDays"
min="0"
step="1"
vn-acl="deliveryBoss">
vn-acl="deliveryBoss"
rule>
</vn-input-number>
<vn-input-time
label="Closing"
model="$ctrl.zone.hour"
vn-acl="deliveryBoss">
field="$ctrl.zone.hour"
vn-acl="deliveryBoss"
rule>
</vn-input-time>
</vn-horizontal>
<vn-horizontal>
<vn-input-number
label="Price"
model="$ctrl.zone.price"
field="$ctrl.zone.price"
min="0"
step="0.01"
vn-acl="deliveryBoss">
vn-acl="deliveryBoss"
rule>
</vn-input-number>
<vn-input-number
label="Bonus"
model="$ctrl.zone.bonus"
field="$ctrl.zone.bonus"
min="0"
step="0.01"
vn-acl="deliveryBoss">
vn-acl="deliveryBoss"
rule>
</vn-input-number>
</vn-horizontal>
<vn-horizontal>
<vn-input-number
vn-one
label="Inflation"
model="$ctrl.zone.inflation"
field="$ctrl.zone.inflation"
min="0"
step="0.01"
vn-acl="deliveryBoss">
vn-acl="deliveryBoss"
rule>
</vn-input-number>
<vn-check
vn-one
label="Volumetric"
field="$ctrl.zone.isVolumetric"
vn-acl="deliveryBoss">
vn-acl="deliveryBoss"
rule>
</vn-check>
</vn-horizontal>
</vn-card>

View File

@ -3,55 +3,72 @@
vn-id="watcher"
data="$ctrl.zone"
form="form"
save="post">
save="post"
rule="Zone">
</vn-watcher>
<div class="content-block">
<form name="form" vn-http-submit="$ctrl.onSubmit()" compact>
<vn-card class="vn-pa-lg">
<vn-horizontal>
<vn-textfield vn-two vn-focus
<vn-textfield
vn-one
vn-focus
label="Name"
field="$ctrl.zone.name">
</vn-textfield>
</vn-horizontal>
<vn-horizontal>
<vn-autocomplete vn-one
<vn-autocomplete
vn-one
field="$ctrl.zone.warehouseFk"
url="/agency/api/Warehouses"
show-field="name"
value-field="id"
label="Warehouse">
label="Warehouse"
rule>
</vn-autocomplete>
<vn-autocomplete vn-one
<vn-autocomplete
vn-one
field="$ctrl.zone.agencyModeFk"
url="/agency/api/AgencyModes/isActive"
show-field="name"
value-field="id"
label="Agency">
label="Agency"
rule>
</vn-autocomplete>
</vn-horizontal>
<vn-horizontal>
<vn-input-number vn-two
<vn-input-number
vn-two
label="Traveling days"
model="$ctrl.zone.travelingDays"
min="0" step="1">
field="$ctrl.zone.travelingDays"
min="0"
step="1"
rule>
</vn-input-number>
<vn-input-time vn-two
<vn-input-time
vn-two
label="Estimated hour (ETD)"
model="$ctrl.zone.hour"
rule="zone.hour">
field="$ctrl.zone.hour"
rule>
</vn-input-time>
</vn-horizontal>
<vn-horizontal>
<vn-input-number vn-one
<vn-input-number
vn-one
label="Price"
model="$ctrl.zone.price"
min="0" step="0.01">
min="0"
step="0.01"
rule>
</vn-input-number>
<vn-input-number vn-one
<vn-input-number
vn-one
label="Bonus"
model="$ctrl.zone.bonus"
min="0" step="0.01">
min="0"
step="0.01"
rule>
</vn-input-number>
</vn-horizontal>
<vn-horizontal>

View File

@ -5,12 +5,18 @@
form="form"
save="patch">
</vn-watcher>
<form name="form" ng-submit="$ctrl.onSubmit()">
<form
name="form"
ng-submit="$ctrl.onSubmit()"
rule="Zone">
<vn-card class="vn-pa-lg">
<vn-horizontal>
<vn-textfield vn-two vn-focus
<vn-textfield
vn-one
vn-focus
label="Name"
field="$ctrl.zone.name">
field="$ctrl.zone.name"
rule>
</vn-textfield>
</vn-horizontal>
<vn-horizontal>
@ -20,7 +26,8 @@
url="/agency/api/Warehouses"
show-field="name"
value-field="id"
label="Warehouse">
label="Warehouse"
rule>
</vn-autocomplete>
<vn-autocomplete
vn-one
@ -28,35 +35,42 @@
url="/agency/api/AgencyModes/isActive"
show-field="name"
value-field="id"
label="Agency">
label="Agency"
rule>
</vn-autocomplete>
</vn-horizontal>
<vn-horizontal>
<vn-input-number
vn-two
vn-one
min="0"
step="1"
label="Traveling days"
field="$ctrl.zone.travelingDays">
field="$ctrl.zone.travelingDays"
rule>
</vn-input-number>
<vn-input-time
vn-two
vn-one
label="Estimated hour (ETD)"
field="$ctrl.zone.hour">
field="$ctrl.zone.hour"
rule>
</vn-input-time>
</vn-horizontal>
<vn-horizontal>
<vn-input-number vn-one
<vn-input-number
vn-one
label="Price"
field="$ctrl.zone.price"
min="0.00"
step="0.50">
step="0.50"
rule>
</vn-input-number>
<vn-input-number vn-one
<vn-input-number
vn-one
label="Bonus"
field="$ctrl.zone.bonus"
min="0.00"
step="0.50">
step="0.50"
rule>
</vn-input-number>
</vn-horizontal>
</vn-card>

View File

@ -102,38 +102,38 @@
<vn-vertical ng-if="$ctrl.eventType == 'day'">
<vn-date-picker
label="Day"
model="$ctrl.selected.from">
field="$ctrl.selected.from">
</vn-date-picker>
</vn-vertical>
<vn-horizontal ng-if="$ctrl.eventType == 'range'">
<vn-date-picker
label="From"
model="$ctrl.selected.from">
field="$ctrl.selected.from">
</vn-date-picker>
<vn-date-picker
label="To"
model="$ctrl.selected.to">
field="$ctrl.selected.to">
</vn-date-picker>
</vn-horizontal>
<vn-input-time
label="Closing"
model="$ctrl.selected.hour">
field="$ctrl.selected.hour">
</vn-input-time>
<vn-input-number
label="Traveling days"
model="$ctrl.selected.travelingDays"
field="$ctrl.selected.travelingDays"
min="0"
step="1">
</vn-input-number>
<vn-input-number
label="Price"
model="$ctrl.selected.price"
field="$ctrl.selected.price"
min="0"
step="0.01">
</vn-input-number>
<vn-input-number
label="Bonus"
model="$ctrl.selected.bonus"
field="$ctrl.selected.bonus"
min="0"
step="0.01">
</vn-input-number>

View File

@ -22,8 +22,8 @@
vn-one
disabled="true"
label="Created"
model="$ctrl.claim.created"
ini-options="{enableTime: true, dateFormat: 'd-m-Y', time_24hr: true}">
field="$ctrl.claim.created"
options="{enableTime: true}">
</vn-date-picker>
</vn-horizontal>
<vn-horizontal class="vn-py-sm">

View File

@ -37,8 +37,10 @@
<vn-td center>{{::saleClaimed.sale.ticket.landed | dateTime:'dd/MM/yyyy'}}</vn-td>
<vn-td number>{{::saleClaimed.sale.quantity}}</vn-td>
<vn-td>
<vn-input-number vn-focus min="0" step="1"
model="saleClaimed.quantity"
<vn-input-number
vn-focus min="0"
step="1"
field="saleClaimed.quantity"
on-change="$ctrl.setClaimedQuantity(saleClaimed.id, saleClaimed.quantity)">
</vn-input-number>
</vn-td>
@ -138,13 +140,11 @@
<vn-input-number
vn-focus
label="Discount"
model="$ctrl.newDiscount"
field="$ctrl.newDiscount"
type="text"
step="0.01"
on-change="$ctrl.updateDiscount()">
<t-right-icons>
<span class="filter"></span>
</t-right-icons>
on-change="$ctrl.updateDiscount()"
suffix="€">
</vn-input-number>
<div class="simulator">
<p class="simulatorTitle" translate>New price</p>

View File

@ -62,7 +62,7 @@
<vn-date-picker
vn-one
label="Created"
model="filter.created">
field="filter.created">
</vn-date-picker>
</vn-horizontal>
<vn-horizontal class="vn-mt-lg">

View File

@ -8,10 +8,10 @@
</vn-horizontal>
<div class="vn-pa-md">
<vn-horizontal>
<vn-date-picker vn-one
<vn-date-picker
vn-one
label="Date"
model="$ctrl.receipt.payed"
ini-options="{dateFormat: 'd-m-Y', time_24hr: true}">
field="$ctrl.receipt.payed">
</vn-date-picker>
<vn-autocomplete vn-one
url="/api/Companies"
@ -29,9 +29,13 @@
value-field="id"
field="$ctrl.receipt.bankFk">
</vn-autocomplete>
<vn-input-number vn-one vn-focus
<vn-input-number
vn-one
vn-focus
label="Amount"
field="$ctrl.receipt.amountPaid" step="0.01">
field="$ctrl.receipt.amountPaid"
step="0.01"
rule>
</vn-input-number>
</vn-horizontal>
</div>

View File

@ -17,10 +17,14 @@
fields="['ibanRequired']"
initial-data="$ctrl.client.payMethod">
</vn-autocomplete>
<vn-input-number vn-one min="0" step="1"
<vn-input-number
vn-one
min="0"
step="1"
label="Due day"
field="$ctrl.client.dueDay"
vn-acl="salesAssistant">
vn-acl="salesAssistant"
rule>
</vn-input-number>
</vn-horizontal>
<vn-horizontal>
@ -31,7 +35,8 @@
on-change="$ctrl.autofillBic()"
vn-acl="salesAssistant">
</vn-textfield>
<vn-autocomplete vn-one
<vn-autocomplete
vn-one
label="Swift / BIC"
url="/client/api/BankEntities"
field="$ctrl.client.bankEntityFk"
@ -51,15 +56,17 @@
</vn-one>
</vn-horizontal>
</tpl-item>
<append>
<vn-icon-button
vn-auto
class="vn-my-md"
icon="add_circle"
vn-tooltip="New bank entity"
vn-dialog="bankEntityDialog"
vn-acl="salesAssistant">
</vn-icon-button>
</append>
</vn-autocomplete>
<vn-icon-button
vn-auto
class="vn-my-md"
icon="add_circle"
vn-tooltip="New bank entity"
vn-dialog="bankEntityDialog"
vn-acl="salesAssistant">
</vn-icon-button>
</vn-horizontal>
<vn-horizontal class="vn-py-sm">
<vn-one>

View File

@ -1,22 +1,26 @@
<form name="form" ng-submit="$ctrl.onSubmit()" compact>
<vn-card class="vn-pa-lg">
<vn-horizontal>
<vn-input-number vn-one min="0"
<vn-input-number
vn-one
min="0"
label="Credit"
model="$ctrl.creditClassification.credit",
field="$ctrl.creditClassification.credit"
rule="creditInsurance.credit"
vn-focus>
</vn-input-number>
<vn-input-number vn-one min="0" step="1"
<vn-input-number
vn-one
min="0"
step="1"
label="Grade"
model="$ctrl.creditClassification.grade"
field="$ctrl.creditClassification.grade"
rule="CreditInsurance.grade">
</vn-input-number>
<vn-date-picker
vn-one
label="Since"
model="$ctrl.creditClassification.started"
ini-options="{enableTime: true, dateFormat: 'd-m-Y', time_24hr: true}">
field="$ctrl.creditClassification.started">
</vn-date-picker>
</vn-horizontal>
</vn-card>

View File

@ -8,22 +8,27 @@
<form name="form" ng-submit="$ctrl.onSubmit()" compact>
<vn-card class="vn-pa-lg">
<vn-horizontal>
<vn-input-number vn-one min="0"
<vn-input-number
vn-one
min="0"
label="Credit"
model="$ctrl.insurance.credit"
field="$ctrl.insurance.credit"
rule="CreditInsurance.credit"
vn-focus>
</vn-input-number>
<vn-date-picker vn-one
<vn-date-picker
vn-one
label="Date"
model="$ctrl.insurance.created"
ini-options="{enableTime: true, dateFormat: 'd-m-Y', time_24hr: true}">
field="$ctrl.insurance.created">
</vn-date-picker>
</vn-horizontal>
<vn-horizontal>
<vn-input-number vn-one min="0" step="1"
<vn-input-number
vn-one
min="0"
step="1"
label="Grade"
model="$ctrl.insurance.grade"
field="$ctrl.insurance.grade"
rule="CreditInsurance.grade">
</vn-input-number>
</vn-horizontal>

View File

@ -3,38 +3,36 @@
url="/client/api/CreditInsurances"
link="{creditClassification: $ctrl.$stateParams.classificationId}"
limit="20"
data="insurances" auto-load="false">
data="insurances"
auto-load="true">
</vn-crud-model>
<vn-vertical compact>
<vn-card class="vn-pa-lg">
<vn-vertical>
<vn-table model="model">
<vn-thead>
<vn-tr>
<vn-th number>Credit</vn-th>
<vn-th number>Grade</vn-th>
<vn-th>Created</vn-th>
</vn-tr>
</vn-thead>
<vn-tbody>
<vn-tr ng-repeat="insurance in insurances">
<vn-td number>{{::insurance.credit | currency: 'EUR': 2}}</vn-td>
<vn-td number>{{::insurance.grade}}</vn-td>
<vn-td>{{::insurance.created | dateTime: 'dd/MM/yyyy'}}</vn-td>
</vn-tr>
</vn-tbody>
</vn-table>
</vn-vertical>
<vn-pagination model="model"></vn-pagination>
<div class="vn-w-xs">
<vn-data-viewer model="model">
<vn-card>
<vn-table model="model">
<vn-thead>
<vn-tr>
<vn-th>Created</vn-th>
<vn-th number>Grade</vn-th>
<vn-th number>Credit</vn-th>
</vn-tr>
</vn-thead>
<vn-tbody>
<vn-tr ng-repeat="insurance in insurances">
<vn-td>{{::insurance.created | dateTime: 'dd/MM/yyyy'}}</vn-td>
<vn-td number>{{::insurance.grade}}</vn-td>
<vn-td number>{{::insurance.credit | currency: 'EUR': 2}}</vn-td>
</vn-tr>
</vn-tbody>
</vn-table>
</vn-card>
<vn-button-bar>
<button
class="mdl-button mdl-button--raised mdl-button--colored"
translate
ui-sref="client.card.creditInsurance.index">Back</button>
</vn-button-bar>
</vn-vertical>
<a ui-sref="client.card.creditInsurance.insurance.create({classificationId: {{$ctrl.$stateParams.classificationId}}})"
fixed-bottom-right vn-tooltip="New credit" vn-bind="+" ng-if="!$ctrl.isClosed">
</vn-data-viewer>
</div>
<a
ng-if="!$ctrl.isClosed"
ui-sref="client.card.creditInsurance.insurance.create({classificationId: {{$ctrl.$stateParams.classificationId}}})"
fixed-bottom-right
vn-tooltip="New credit"
vn-bind="+">
<vn-float-button icon="add"></vn-float-button>
</a>

View File

@ -8,10 +8,13 @@
<form name="form" ng-submit="$ctrl.onSubmit()" compact>
<vn-card class="vn-pa-lg">
<vn-horizontal>
<vn-input-number vn-one min="0"
<vn-input-number
vn-one
min="0"
label="Credit"
field="$ctrl.client.credit"
vn-focus>
vn-focus
rule>
</vn-input-number>
</vn-horizontal>
</vn-card>

View File

@ -8,28 +8,33 @@
<form name="form" ng-submit="$ctrl.onSubmit()" compact>
<vn-card class="vn-pa-lg">
<vn-horizontal>
<vn-input-number vn-one vn-focus
<vn-input-number
vn-one
vn-focus
label="Amount"
field="$ctrl.greuge.amount" step="0.01">
field="$ctrl.greuge.amount"
step="0.01"
rule>
</vn-input-number>
<vn-date-picker vn-one
label="Date"
model="$ctrl.greuge.shipped"
ini-options="{enableTime: true, dateFormat: 'd-m-Y h:i', time_24hr: true}">
<vn-date-picker
vn-one
label="Date"
field="$ctrl.greuge.shipped">
</vn-date-picker>
</vn-horizontal>
<vn-horizontal>
<vn-textfield
vn-one
argin-medium-right
vn-one
label="Comment"
field="$ctrl.greuge.description">
field="$ctrl.greuge.description"
rule>
</vn-textfield>
<vn-autocomplete
vn-one
field="$ctrl.greuge.greugeTypeFk"
url="/client/api/greugeTypes"
label="Type">
label="Type"
rule>
</vn-autocomplete>
</vn-horizontal>
</vn-card>

View File

@ -8,24 +8,30 @@
<form name="form" ng-submit="$ctrl.onSubmit()" compact>
<vn-card class="vn-pa-lg">
<vn-horizontal>
<vn-date-picker vn-one
<vn-date-picker
vn-one
label="Since"
model="$ctrl.recovery.started"
vn-focus
ini-options="{enableTime: true}">
field="$ctrl.recovery.started"
vn-focus>
</vn-date-picker>
<vn-date-picker vn-one
<vn-date-picker
vn-one
label="To"
model="$ctrl.recovery.finished"
ini-options="{enableTime: true}">
field="$ctrl.recovery.finished">
</vn-date-picker>
<vn-input-number vn-one vn-focus
<vn-input-number
vn-one
vn-focus
label="Amount"
field="$ctrl.recovery.amount" step="0.01">
field="$ctrl.recovery.amount"
step="0.01"
rule>
</vn-input-number>
<vn-input-number vn-one
<vn-input-number
vn-one
label="Period"
field="$ctrl.recovery.period">
field="$ctrl.recovery.period"
rule>
</vn-input-number>
</vn-horizontal>
</vn-card>

View File

@ -43,17 +43,17 @@
<vn-date-picker
vn-one
label="Issued"
model="filter.issued">
field="filter.issued">
</vn-date-picker>
<vn-date-picker
vn-one
label="Created"
model="filter.created">
field="filter.created">
</vn-date-picker>
<vn-date-picker
vn-one
label="Due date"
model="filter.dued">
field="filter.dued">
</vn-date-picker>
</vn-horizontal>
<vn-horizontal class="vn-mt-lg">

View File

@ -62,24 +62,36 @@
label="Reference"
field="$ctrl.item.comment">
</vn-textfield>
<vn-input-number vn-one min="0"
<vn-input-number
vn-one
min="0"
label="Size"
field="$ctrl.item.size">
field="$ctrl.item.size"
rule>
</vn-input-number>
<vn-input-number vn-one min="0"
<vn-input-number
vn-one
min="0"
label="stems"
field="$ctrl.item.stems">
field="$ctrl.item.stems"
rule>
</vn-input-number>
</vn-horizontal>
<vn-horizontal>
<vn-input-number vn-one min="0"
<vn-input-number
vn-one
min="0"
step="0.01"
label="Density"
field="$ctrl.item.density">
field="$ctrl.item.density"
rule>
</vn-input-number>
<vn-input-number vn-one min="0"
<vn-input-number
vn-one
min="0"
label="Relevancy"
field="$ctrl.item.relevancy">
field="$ctrl.item.relevancy"
rule>
</vn-input-number>
</vn-horizontal>
<vn-horizontal>

View File

@ -12,8 +12,7 @@
<vn-date-picker
vn-one
label="Since"
model="$ctrl.date"
ini-options="{dateFormat: 'd-m-Y'}">
field="$ctrl.date">
</vn-date-picker>
<!--datepicker-->
</vn-horizontal>

View File

@ -42,12 +42,12 @@
<vn-date-picker
vn-one
label="From"
model="filter.from">
field="filter.from">
</vn-date-picker>
<vn-date-picker
vn-one
label="To"
model="filter.to">
field="filter.to">
</vn-date-picker>
</vn-horizontal>
<vn-horizontal>

View File

@ -73,8 +73,8 @@
<vn-td-editable disabled="request.isOk === 0" number>
<text>{{request.itemFk}}</text>
<field>
<vn-input-number vn-focus
model="request.itemFk"
<vn-input-number
field="request.itemFk"
on-change="$ctrl.confirmRequest(request)">
</vn-input-number>
</field>
@ -90,8 +90,8 @@
<vn-td-editable disabled="request.isOk === 0" number>
<text number>{{request.saleQuantity}}</text>
<field>
<vn-input-number vn-focus
model="request.saleQuantity"
<vn-input-number
field="request.saleQuantity"
on-change="$ctrl.changeQuantity(request)">
</vn-input-number>
</field>

View File

@ -43,8 +43,7 @@
<vn-date-picker
vn-one
label="Landed"
model="$ctrl.order.landed"
ini-options="{enableTime: false}">
field="$ctrl.order.landed">
</vn-date-picker>
<vn-autocomplete
vn-one

View File

@ -22,8 +22,7 @@
</vn-autocomplete>
<vn-date-picker
label="Landed"
model="$ctrl.landed"
ini-options="{enableTime: false}">
field="$ctrl.landed">
</vn-date-picker>
<vn-autocomplete
disabled="!$ctrl.clientFk || !$ctrl.landed"

View File

@ -55,10 +55,11 @@
</div>
</vn-td>
<vn-td>
<vn-input-number min="0"
<vn-input-number
min="0"
name="quantity"
label="Qty."
model="price.quantity"
field="price.quantity"
step="price.grouping"
on-change="$ctrl.validate()">
</vn-input-number>

View File

@ -42,13 +42,15 @@
</vn-autocomplete>
</vn-horizontal>
<vn-horizontal>
<vn-date-picker vn-one
<vn-date-picker
vn-one
label="From landed"
model="filter.from">
field="filter.from">
</vn-date-picker>
<vn-date-picker vn-one
<vn-date-picker
vn-one
label="To landed"
model="filter.to">
field="filter.to">
</vn-date-picker>
</vn-horizontal>
<vn-horizontal>

View File

@ -31,8 +31,7 @@
<vn-date-picker
vn-one
label="Created"
model="$ctrl.route.created"
ini-options="{dateFormat: 'd-m-Y'}">
field="$ctrl.route.created">
</vn-date-picker>
<vn-autocomplete
vn-one
@ -47,29 +46,32 @@
<vn-input-number
vn-one
label="Km start"
field="$ctrl.route.kmStart">
field="$ctrl.route.kmStart"
rule>
</vn-input-number>
<vn-input-number
vn-one
label="Km end"
model="$ctrl.route.kmEnd">
field="$ctrl.route.kmEnd"
rule>
</vn-input-number>
</vn-horizontal>
<vn-horizontal>
<vn-input-time
label="Hour started"
model="$ctrl.route.started">
field="$ctrl.route.started">
</vn-input-time>
<vn-input-time
label="Hour finished"
model="$ctrl.route.finished">
field="$ctrl.route.finished">
</vn-input-time>
</vn-horizontal>
<vn-horizontal>
<vn-textfield
vn-one
label="Description"
field="$ctrl.route.description" vn-focus>
field="$ctrl.route.description"
vn-focus>
</vn-textfield>
</vn-horizontal>
</vn-card>

View File

@ -22,8 +22,7 @@
<vn-date-picker
vn-one
label="Created"
model="$ctrl.route.created"
ini-options="{dateFormat: 'd-m-Y'}">
field="$ctrl.route.created">
</vn-date-picker>
</vn-horizontal>
<vn-horizontal>

View File

@ -30,13 +30,15 @@
</vn-autocomplete>
</vn-horizontal>
<vn-horizontal>
<vn-date-picker vn-one
<vn-date-picker
vn-one
label="From"
model="filter.from">
field="filter.from">
</vn-date-picker>
<vn-date-picker vn-one
<vn-date-picker
vn-one
label="To"
model="filter.to">
field="filter.to">
</vn-date-picker>
</vn-horizontal>
<vn-horizontal>

View File

@ -40,14 +40,16 @@
</vn-autocomplete>
</vn-horizontal>
<vn-horizontal>
<vn-date-picker vn-one
<vn-date-picker
vn-one
label="Shipped"
model="$ctrl.shipped"
ini-options="{enableTime: true, dateFormat: 'd-m-Y h:i'}">
field="$ctrl.shipped"
options="{enableTime: true}">
</vn-date-picker>
<vn-date-picker vn-one
<vn-date-picker
vn-one
label="Landed"
model="$ctrl.landed">
field="$ctrl.landed">
</vn-date-picker>
<vn-autocomplete vn-one
url="/api/Companies"

View File

@ -22,8 +22,7 @@
</vn-autocomplete>
<vn-date-picker
label="Landed"
model="$ctrl.landed"
ini-options="{enableTime: false}">
field="$ctrl.landed">
</vn-date-picker>
<vn-autocomplete
disabled="!$ctrl.warehouseFk && (!$ctrl.clientFk || !$ctrl.landed)"

View File

@ -178,7 +178,12 @@
<h5 style="text-align: center">
<span translate>Change shipped hour</span>
</h5>
<vn-input-time vn-id="newShipped" vn-one model="$ctrl.newShipped" label="Shipped hour"></vn-input-time>
<vn-input-time
vn-id="newShipped"
vn-one
field="$ctrl.newShipped"
label="Shipped hour">
</vn-input-time>
</div>
</tpl-body>
<tpl-buttons>

View File

@ -25,9 +25,11 @@
field="package.packagingFk">
<tpl-item>{{itemFk}} : {{name}}</tpl-item>
</vn-autocomplete>
<vn-input-number vn-one step="1"
<vn-input-number
vn-one
step="1"
label="Quantity"
model="package.quantity"
field="package.quantity"
rule="TicketPackaging.quantity">
</vn-input-number>
<vn-textfield

View File

@ -22,14 +22,20 @@
</vn-autocomplete>
</vn-horizontal>
<vn-horizontal>
<vn-input-number vn-one min="1"
<vn-input-number
vn-one
min="1"
label="Quantity"
field="$ctrl.ticketRequest.quantity">
field="$ctrl.ticketRequest.quantity"
rule>
</vn-input-number>
<vn-input-number vn-one min="0"
<vn-input-number
vn-one
min="0"
label="Price"
step="0.01"
field="$ctrl.ticketRequest.price">
field="$ctrl.ticketRequest.price"
rule>
</vn-input-number>
</vn-horizontal>
</vn-card>

View File

@ -5,11 +5,9 @@
<vn-input-number
vn-focus
label="Discount"
model="$ctrl.newDiscount"
on-change="$ctrl.updateDiscount()">
<t-right-icons>
<span class="filter">%</span>
</t-right-icons>
field="$ctrl.newDiscount"
on-change="$ctrl.updateDiscount()"
suffix="%">
</vn-input-number>
<div class="simulator">
<p class="simulatorTitle" translate>New price</p>

View File

@ -111,8 +111,10 @@
ng-click="$ctrl.showDescriptor($event, sale.itemFk)">
{{sale.itemFk | zeroFill:6}}
</span>
<vn-autocomplete ng-if="!sale.itemFk" vn-focus vn-one
<vn-autocomplete
ng-if="!sale.itemFk"
vn-focus
vn-one
url="/api/Items"
field="sale.itemFk"
show-field="name"
@ -127,15 +129,16 @@
<vn-td-editable ng-if="sale.id" disabled="!$ctrl.isEditable" number>
<text>{{sale.quantity}}</text>
<field>
<vn-input-number vn-focus
model="sale.quantity"
<vn-input-number
vn-focus
field="sale.quantity"
on-change="$ctrl.onChangeQuantity(sale)">
</vn-input-number>
</field>
</vn-td-editable>
<vn-td ng-if="!sale.id" number>
<vn-input-number
model="sale.quantity"
field="sale.quantity"
on-change="$ctrl.onChangeQuantity(sale)">
</vn-input-number>
</vn-td>
@ -208,13 +211,11 @@
<vn-input-number
vn-focus
label="Price"
model="$ctrl.editedPrice"
field="$ctrl.editedPrice"
type="text"
step="0.01"
on-change="$ctrl.updatePrice()">
<t-right-icons>
<span class="filter"></span>
</t-right-icons>
on-change="$ctrl.updatePrice()"
suffix="€">
</vn-input-number>
<div class="simulator">
<p class="simulatorTitle" translate>New price</p>
@ -289,8 +290,9 @@
<vn-td-editable number shrink>
<text>{{sale.quantity}}</text>
<field>
<vn-input-number vn-focus
model="sale.quantity">
<vn-input-number
vn-focus
field="sale.quantity">
</vn-input-number>
</field>
</vn-td-editable>

View File

@ -30,18 +30,19 @@
<vn-date-picker
vn-one
label="From"
model="filter.from">
field="filter.from">
</vn-date-picker>
<vn-date-picker
vn-one
label="To"
model="filter.to">
field="filter.to">
</vn-date-picker>
<vn-input-number vn-one
<vn-input-number
vn-one
min="0"
step="1"
label="Days onward"
model="filter.scopeDays"
field="filter.scopeDays"
display-controls="true">
</vn-input-number>
</vn-horizontal>

View File

@ -29,14 +29,18 @@
ng-click="$ctrl.newServiceTypeDialog($index)"
vn-acl="administrative">
</vn-icon-button>
<vn-input-number vn-one min="0" step="1"
<vn-input-number
vn-one min="0"
step="1"
label="Quantity"
model="service.quantity"
field="service.quantity"
rule="TicketService.quantity">
</vn-input-number>
<vn-input-number vn-one
<vn-input-number
vn-one
label="Price"
model="service.price" step="0.01">
field="service.price"
step="0.01">
</vn-input-number>
<vn-autocomplete vn-one
url="/api/TaxClasses"

View File

@ -39,12 +39,12 @@
<vn-date-picker
vn-one
label="Shipped"
model="filter.shipped">
field="filter.shipped">
</vn-date-picker>
<vn-date-picker
vn-one
label="Landed"
model="filter.landed">
field="filter.landed">
</vn-date-picker>
</vn-horizontal>
<vn-horizontal>

View File

@ -77,7 +77,12 @@
<h5 style="text-align: center">
<span translate>Add time</span>
</h5>
<vn-input-time vn-one model="$ctrl.newTime" label="Hour" vn-focus></vn-input-time>
<vn-input-time
vn-one
field="$ctrl.newTime"
label="Hour"
vn-focus>
</vn-input-time>
</div>
</tpl-body>
<tpl-buttons>