merge
This commit is contained in:
parent
cadbb2b6c2
commit
fae56408bb
|
@ -1,3 +1,3 @@
|
|||
import './ngModule';
|
||||
import './config';
|
||||
import './login/index';
|
||||
import './login/login';
|
||||
|
|
|
@ -76,6 +76,6 @@ export default class Controller {
|
|||
Controller.$inject = ['$element', '$scope', '$window', '$http'];
|
||||
|
||||
ngModule.component('vnLogin', {
|
||||
template: require('./index.html'),
|
||||
template: require('./login.html'),
|
||||
controller: Controller
|
||||
});
|
|
@ -1,46 +0,0 @@
|
|||
<vn-watcher
|
||||
vn-id="watcher"
|
||||
url="/client/api/Addresses"
|
||||
id-field="id"
|
||||
data="$ctrl.address"
|
||||
form="form">
|
||||
</vn-watcher>
|
||||
<form name="form" ng-submit="$ctrl.onSubmit()" pad-medium>
|
||||
<vn-card >
|
||||
<vn-vertical pad-large>
|
||||
<vn-title>Consignatario</vn-title>
|
||||
<vn-horizontal>
|
||||
<vn-check vn-one label="Predeterminado" field="$ctrl.address.default"></vn-check>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-textfield vn-one label="Consignatario" field="$ctrl.address.consignee" vn-focus></vn-textfield>
|
||||
<vn-textfield vn-one label="Domicilio" field="$ctrl.address.street"></vn-textfield>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-textfield vn-one label="Código Postal" field="$ctrl.address.postcode"></vn-textfield>
|
||||
<vn-textfield vn-one label="Municipio" field="$ctrl.address.city"></vn-textfield>
|
||||
<vn-autocomplete vn-one
|
||||
field="$ctrl.address.provinceFk"
|
||||
url="/client/api/Provinces"
|
||||
show-field="name"
|
||||
value-field="id"
|
||||
label="Provincia">
|
||||
</vn-autocomplete>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-autocomplete vn-one
|
||||
field="$ctrl.address.agencyFk"
|
||||
url="/client/api/AgencyServices"
|
||||
show-field="name"
|
||||
value-field="id"
|
||||
label="Agencia">
|
||||
</vn-autocomplete>
|
||||
<vn-textfield vn-one label="Teléfono" field="$ctrl.address.phone"></vn-textfield>
|
||||
<vn-textfield vn-one label="Móvil" field="$ctrl.address.mobile"></vn-textfield>
|
||||
</vn-horizontal>
|
||||
</vn-vertical>
|
||||
</vn-card>
|
||||
<vn-button-bar>
|
||||
<vn-submit label="Guardar"></vn-submit>
|
||||
</vn-button-bar>
|
||||
</form>
|
|
@ -1,25 +0,0 @@
|
|||
import {module} from '../module';
|
||||
|
||||
class Controller {
|
||||
constructor($scope, $state) {
|
||||
this.$ = $scope;
|
||||
this.$state = $state;
|
||||
this.address = {
|
||||
clientFk: parseInt($state.params.id),
|
||||
enabled: true
|
||||
};
|
||||
}
|
||||
onSubmit() {
|
||||
this.$.watcher.submit().then(
|
||||
() => this.$state.go('clientCard.addresses')
|
||||
);
|
||||
}
|
||||
}
|
||||
Controller.$inject = ['$scope', '$state'];
|
||||
|
||||
export const NAME = 'vnAddressCreate';
|
||||
export const COMPONENT = {
|
||||
template: require('./index.html'),
|
||||
controller: Controller
|
||||
};
|
||||
module.component(NAME, COMPONENT);
|
|
@ -1,48 +0,0 @@
|
|||
<vn-watcher
|
||||
vn-id="watcher"
|
||||
get="true"
|
||||
url="/client/api/Addresses"
|
||||
id-field="id"
|
||||
data="addressData.address"
|
||||
form="form">
|
||||
</vn-watcher>
|
||||
<form name="form" ng-submit="watcher.submitBack()" pad-medium>
|
||||
<vn-card>
|
||||
<vn-vertical pad-large>
|
||||
<vn-title>Consignatario</vn-title>
|
||||
<vn-horizontal>
|
||||
<vn-check vn-one label="Activo" field="addressData.address.enabled"></vn-check>
|
||||
<vn-check vn-one label="Predeterminado" field="addressData.address.default"></vn-check>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-textfield vn-one label="Consignatario" field="addressData.address.consignee" vn-focus></vn-textfield>
|
||||
<vn-textfield vn-one label="Domicilio" field="addressData.address.street"></vn-textfield>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-textfield vn-one label="Código Postal" field="addressData.address.postcode"></vn-textfield>
|
||||
<vn-textfield vn-one label="Municipio" field="addressData.address.city"></vn-textfield>
|
||||
<vn-autocomplete vn-one
|
||||
field="addressData.address.provinceFk"
|
||||
url="/client/api/Provinces"
|
||||
show-field="name"
|
||||
value-field="id"
|
||||
label="Provincia">
|
||||
</vn-autocomplete>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-autocomplete vn-one
|
||||
field="addressData.address.defaultAgencyFk"
|
||||
url="/client/api/AgencyServices"
|
||||
show-field="name"
|
||||
value-field="id"
|
||||
label="Agencia">
|
||||
</vn-autocomplete>
|
||||
<vn-textfield vn-one label="Teléfono" field="addressData.address.phone"></vn-textfield>
|
||||
<vn-textfield vn-one label="Móvil" field="addressData.address.mobile"></vn-textfield>
|
||||
</vn-horizontal>
|
||||
</vn-vertical>
|
||||
</vn-card>
|
||||
<vn-button-bar>
|
||||
<vn-submit label="Guardar"></vn-submit>
|
||||
</vn-button-bar>
|
||||
</form>
|
|
@ -1,18 +0,0 @@
|
|||
import {module} from '../module';
|
||||
|
||||
class Controller {
|
||||
constructor($stateParams) {
|
||||
this.address = {
|
||||
id: $stateParams.addressId
|
||||
};
|
||||
}
|
||||
}
|
||||
Controller.$inject = ['$stateParams'];
|
||||
|
||||
export const NAME = 'vnAddressEdit';
|
||||
export const COMPONENT = {
|
||||
template: require('./index.html'),
|
||||
controllerAs: 'addressData',
|
||||
controller: Controller
|
||||
};
|
||||
module.component(NAME, COMPONENT);
|
|
@ -1,32 +0,0 @@
|
|||
<mg-ajax path="/client/api/Clients/{{index.params.id}}/addressesList" options="vnIndex"></mg-ajax>
|
||||
<vn-vertical pad-medium>
|
||||
<vn-card>
|
||||
<vn-vertical pad-large>
|
||||
<vn-horizontal>
|
||||
<vn-title vn-one>Consignatario</vn-title>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal ng-repeat="i in index.model" class="pad-medium-top" style="align-items: center;">
|
||||
<vn-auto style="border-radius: .5em;" class="pad-small border-solid"
|
||||
ng-class="{'bg-dark-item': i.default,'bg-opacity-item': !i.enabled && !i.default}">
|
||||
<vn-horizontal style="align-items: center;">
|
||||
<vn-auto>
|
||||
<div><b>{{i.consignee}}</b></div>
|
||||
<div>{{i.street}}</div>
|
||||
<div>{{i.city}}, {{i.province}}</div>
|
||||
<div>{{i.phone}}, {{i.mobile}}</div>
|
||||
</vn-auto>
|
||||
<a vn-empty ui-sref="clientCard.addresses.edit({addressId: {{i.id}}})">
|
||||
<vn-icon-button icon="edit"></vn-icon-button>
|
||||
</a>
|
||||
</vn-horizontal>
|
||||
</vn-auto>
|
||||
</vn-horizontal>
|
||||
</vn-vertical>
|
||||
</vn-card>
|
||||
<vn-paging index="index"></vn-paging>
|
||||
<vn-float-button
|
||||
fixed-bottom-right
|
||||
ui-sref="clientCard.addresses.create"
|
||||
icon="add">
|
||||
</vn-float-button>
|
||||
</vn-vertical>
|
|
@ -1,6 +0,0 @@
|
|||
import {module} from '../module';
|
||||
|
||||
export const component = {
|
||||
template: require('./index.html')
|
||||
};
|
||||
module.component('vnClientAddresses', component);
|
|
@ -1,48 +0,0 @@
|
|||
<mg-ajax path="/client/api/Clients/{{put.params.id}}" options="vnPut"></mg-ajax>
|
||||
<vn-watcher
|
||||
vn-id="watcher"
|
||||
data="$ctrl.client"
|
||||
form="form"
|
||||
save="put">
|
||||
</vn-watcher>
|
||||
<form name="form" ng-submit="watcher.submit()" pad-medium>
|
||||
<vn-card>
|
||||
<vn-vertical pad-large>
|
||||
<vn-title>Datos básicos</vn-title>
|
||||
<vn-horizontal>
|
||||
<vn-textfield vn-one label="Nombre" field="$ctrl.client.name" vn-focus></vn-textfield>
|
||||
<vn-textfield vn-one label="NIF/CIF" field="$ctrl.client.fi"></vn-textfield>
|
||||
<vn-textfield autofocus vn-one label="Razón social" field="$ctrl.client.socialName"></vn-textfield>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-textfield vn-one label="Teléfono" field="$ctrl.client.phone"></vn-textfield>
|
||||
<vn-textfield vn-one label="Móvil" field="$ctrl.client.mobile"></vn-textfield>
|
||||
<vn-textfield vn-one label="Fax" field="$ctrl.client.fax"></vn-textfield>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-textfield vn-one label="Email" field="$ctrl.client.email"></vn-textfield>
|
||||
<vn-autocomplete vn-one
|
||||
initial-value="$ctrl.client.salesPerson"
|
||||
field="$ctrl.client.salesPersonFk"
|
||||
url="/client/api/Employees"
|
||||
show-field="name"
|
||||
value-field="id"
|
||||
select-fields="surname"
|
||||
label="Comercial">
|
||||
<tpl-item>
|
||||
{{::i.name}} {{::i.surname}}
|
||||
</tpl-item>
|
||||
</vn-autocomplete>
|
||||
<vn-autocomplete vn-one
|
||||
initial-value="$ctrl.client.contactChannel"
|
||||
field="$ctrl.client.contactChannelFk"
|
||||
url="/client/api/ContactChannels/scope"
|
||||
label="Canal">
|
||||
</vn-autocomplete>
|
||||
</vn-horizontal>
|
||||
</vn-vertical>
|
||||
</vn-card>
|
||||
<vn-button-bar>
|
||||
<vn-submit label="Guardar"></vn-submit>
|
||||
</vn-button-bar>
|
||||
</form>
|
|
@ -1,9 +0,0 @@
|
|||
import {module} from '../module';
|
||||
|
||||
export const component = {
|
||||
template: require('./index.html'),
|
||||
bindings: {
|
||||
client: '<'
|
||||
}
|
||||
};
|
||||
module.component('vnClientBasicData', component);
|
|
@ -1,43 +0,0 @@
|
|||
<mg-ajax path="/client/api/Clients/{{put.params.id}}" options="vnPut"></mg-ajax>
|
||||
<vn-watcher
|
||||
vn-id="watcher"
|
||||
data="bill.client"
|
||||
form="form"
|
||||
save="put">
|
||||
</vn-watcher>
|
||||
<form name="form" ng-submit="watcher.submit()" pad-medium>
|
||||
<vn-card margin-small-bottom>
|
||||
<vn-vertical pad-large>
|
||||
<vn-title>Información de facturación</vn-title>
|
||||
<vn-horizontal>
|
||||
<vn-autocomplete vn-two
|
||||
field="bill.client.payMethodFk"
|
||||
url="/client/api/PayMethods"
|
||||
select-fields="ibanRequired"
|
||||
initial-data="bill.client.payMethod"
|
||||
label="Forma de pago">
|
||||
</vn-autocomplete>
|
||||
<vn-textfield vn-two label="IBAN" field="bill.client.iban"></vn-textfield>
|
||||
<vn-textfield vn-one label="Vencimiento" field="bill.client.dueDay"></vn-textfield>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-textfield vn-one label="Crédito" field="bill.client.credit"></vn-textfield>
|
||||
<vn-textfield vn-one label="Crédito asegurado" field="bill.client.creditInsurance"></vn-textfield>
|
||||
<vn-check vn-three label="Recargo de equivalencia" field="bill.client.surcharge"></vn-check>
|
||||
</vn-horizontal>
|
||||
</vn-vertical>
|
||||
</vn-card>
|
||||
<vn-card margin-small-bottom>
|
||||
<vn-vertical pad-large>
|
||||
<vn-title>Documentación</vn-title>
|
||||
<vn-horizontal>
|
||||
<vn-check vn-one label="Recibido core VNH" field="bill.client.coreVnh"></vn-check>
|
||||
<vn-check vn-one label="Recibido core VNL" field="bill.client.coreVnl"></vn-check>
|
||||
<vn-check vn-one label="Recibido B2B VNL" field="bill.client.sepaVnl"></vn-check>
|
||||
</vn-horizontal>
|
||||
</vn-vertical>
|
||||
</vn-card>
|
||||
<vn-button-bar>
|
||||
<vn-submit label="Guardar"></vn-submit>
|
||||
</vn-button-bar>
|
||||
</form>
|
|
@ -1,11 +0,0 @@
|
|||
import {module} from '../module';
|
||||
|
||||
export const NAME = 'vnClientBillingData';
|
||||
export const COMPONENT = {
|
||||
template: require('./index.html'),
|
||||
controllerAs: 'bill',
|
||||
bindings: {
|
||||
client: '<'
|
||||
}
|
||||
};
|
||||
module.component(NAME, COMPONENT);
|
|
@ -1,10 +0,0 @@
|
|||
<vn-horizontal>
|
||||
<mg-ajax path="/client/api/Clients/{{edit.params.id}}/card" options="mgEdit" actions="card.client=edit.model;"></mg-ajax>
|
||||
<vn-empty style="min-width: 18em; padding-left: 1em; padding-bottom: 1em;">
|
||||
<vn-descriptor client="card.client" active="card.client.active" class="display-block" ></vn-descriptor>
|
||||
<vn-left-menu></vn-left-menu>
|
||||
</vn-empty>
|
||||
<vn-auto>
|
||||
<vn-vertical style="max-width: 70em; margin: 0 auto;" ui-view></vn-vertical>
|
||||
</vn-auto>
|
||||
</vn-horizontal>
|
|
@ -1,17 +0,0 @@
|
|||
import {module} from '../module';
|
||||
import './style.css';
|
||||
|
||||
export const NAME = 'vnClientCard';
|
||||
|
||||
export default class vnClientCard {
|
||||
constructor() {
|
||||
this.client = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
module.component(NAME, {
|
||||
template: require('./index.html'),
|
||||
controllerAs: 'card',
|
||||
controller: vnClientCard
|
||||
});
|
|
@ -1,28 +0,0 @@
|
|||
<mg-ajax path="/client/api/Clients" options="vnPost"></mg-ajax>
|
||||
<vn-watcher
|
||||
vn-id="watcher"
|
||||
data="$ctrl.client"
|
||||
form="form"
|
||||
save="post">
|
||||
</vn-watcher>
|
||||
<form name="form" ng-submit="$ctrl.onSubmit()" margin-medium>
|
||||
<div style="max-width: 70em; margin: 0 auto;">
|
||||
<vn-card>
|
||||
<vn-vertical pad-large>
|
||||
<vn-title>Crear Cliente</vn-title>
|
||||
<vn-horizontal>
|
||||
<vn-textfield vn-one label="Nombre" field="$ctrl.client.name" vn-focus></vn-textfield>
|
||||
<vn-textfield vn-one label="NIF/CIF" field="$ctrl.client.fi"></vn-textfield>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-textfield vn-one label="Razón social" field="$ctrl.client.socialName"></vn-textfield>
|
||||
<vn-one></vn-one>
|
||||
</vn-horizontal>
|
||||
</vn-vertical>
|
||||
</vn-card>
|
||||
<vn-button-bar>
|
||||
<vn-submit label="Crear y continuar"></vn-submit>
|
||||
<vn-button label="Crear" ng-click="watcher.submitBack()"></vn-button>
|
||||
</vn-button-bar>
|
||||
</div>
|
||||
</form>
|
|
@ -1,23 +0,0 @@
|
|||
import {module} from '../module';
|
||||
|
||||
class Controller {
|
||||
constructor($scope, $state) {
|
||||
this.$scope = $scope;
|
||||
this.$state = $state;
|
||||
this.client = {
|
||||
active: true
|
||||
};
|
||||
}
|
||||
onSubmit() {
|
||||
this.$scope.watcher.submit().then(
|
||||
json => this.$state.go('clientCard.basicData', {id: json.data.id})
|
||||
);
|
||||
}
|
||||
}
|
||||
Controller.$inject = ['$scope', '$state'];
|
||||
|
||||
export const component = {
|
||||
template: require('./index.html'),
|
||||
controller: Controller
|
||||
};
|
||||
module.component('vnClientCreate', component);
|
|
@ -1,15 +0,0 @@
|
|||
<vn-card>
|
||||
<vn-vertical class="margin-medium" pad-medium-top pad-medium-bottom>
|
||||
<vn-horizontal>
|
||||
<vn-one>
|
||||
<i class="material-icons descriptor-icon">person</i>
|
||||
</vn-one>
|
||||
<vn-vertical vn-two>
|
||||
<div class="margin-none">{{descriptor.client.id}}</div>
|
||||
<div class="margin-none">{{descriptor.client.name}}</div>
|
||||
<div class="margin-none">{{descriptor.client.phone}}</div>
|
||||
<vn-switch label="Activo" model="descriptor.active"></vn-switch>
|
||||
</vn-vertical>
|
||||
</vn-horizontal>
|
||||
</vn-vertical>
|
||||
</vn-card>
|
|
@ -1,21 +0,0 @@
|
|||
import {module} from '../module';
|
||||
import './style.css';
|
||||
|
||||
export const NAME = 'vnDescriptor';
|
||||
export const COMPONENT = {
|
||||
template: require('./index.html'),
|
||||
controllerAs: 'descriptor',
|
||||
bindings: {
|
||||
client: '<',
|
||||
active: '<'
|
||||
},
|
||||
controller: function($http, $scope) {
|
||||
var self = this;
|
||||
$scope.$watch('descriptor.active', function(newValue, oldValue) {
|
||||
if (oldValue !== undefined)
|
||||
$http.put(`/client/api/Clients/${self.client.id}/activate`);
|
||||
});
|
||||
}
|
||||
};
|
||||
COMPONENT.controller.$inject = ['$http', '$scope'];
|
||||
module.component(NAME, COMPONENT);
|
|
@ -1,45 +0,0 @@
|
|||
<mg-ajax path="/client/api/Clients/{{put.params.id}}" options="vnPut"></mg-ajax>
|
||||
<vn-watcher
|
||||
vn-id="watcher"
|
||||
data="fiscal.client"
|
||||
form="form"
|
||||
save="put">
|
||||
</vn-watcher>
|
||||
<form name="form" ng-submit="watcher.submit()" pad-medium>
|
||||
<vn-card margin-small-bottom>
|
||||
<vn-vertical pad-large>
|
||||
<vn-title>Datos fiscales y de facturación</vn-title>
|
||||
<vn-horizontal>
|
||||
<vn-check vn-one label="Facturar" field="fiscal.client.hasToInvoice"></vn-check>
|
||||
<vn-check vn-one label="Factura impresa" field="fiscal.client.invoiceByEmail"></vn-check>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-textfield vn-two label="Domicilio fiscal" field="fiscal.client.street" vn-focus></vn-textfield>
|
||||
<vn-textfield vn-one label="Municipio" field="fiscal.client.city"></vn-textfield>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-textfield vn-one label="Código postal" field="fiscal.client.postcode"></vn-textfield>
|
||||
<vn-autocomplete vn-one
|
||||
initial-value="fiscal.client.province"
|
||||
field="fiscal.client.provinceFk"
|
||||
url="/client/api/Provinces"
|
||||
show-field="name"
|
||||
value-field="id"
|
||||
label="Provincia">
|
||||
</vn-autocomplete>
|
||||
<vn-autocomplete vn-one
|
||||
initial-value="fiscal.client.country"
|
||||
field="fiscal.client.countryFk"
|
||||
url="/client/api/Countries"
|
||||
show-field="name"
|
||||
value-field="id"
|
||||
label="País">
|
||||
</vn-autocomplete>
|
||||
</vn-horizontal>
|
||||
</vn-vertical>
|
||||
</vn-card>
|
||||
|
||||
<vn-button-bar>
|
||||
<vn-submit label="Guardar"></vn-submit>
|
||||
</vn-button-bar>
|
||||
</form>
|
|
@ -1,11 +0,0 @@
|
|||
import {module} from '../module';
|
||||
|
||||
export const NAME = 'vnClientFiscalData';
|
||||
export const COMPONENT = {
|
||||
template: require('./index.html'),
|
||||
controllerAs: 'fiscal',
|
||||
bindings: {
|
||||
client: '<'
|
||||
}
|
||||
};
|
||||
module.component(NAME, COMPONENT);
|
|
@ -1,18 +0,0 @@
|
|||
<vn-watcher
|
||||
vn-id="watcher"
|
||||
url="/client/api/ClientObservations"
|
||||
id-field="id"
|
||||
data="newNote.note"
|
||||
form="form">
|
||||
</vn-watcher>
|
||||
<form name="form" ng-submit="newNote.onSubmit()" pad-medium>
|
||||
<vn-card>
|
||||
<vn-vertical pad-large>
|
||||
<vn-title>Nueva nota</vn-title>
|
||||
<vn-textarea label="Nueva nota" model="newNote.note.text" vn-focus padd-medium-top></vn-textarea>
|
||||
</vn-vertical>
|
||||
</vn-card>
|
||||
<vn-button-bar>
|
||||
<vn-submit label="Guardar"></vn-submit>
|
||||
</vn-button-bar>
|
||||
</form>
|
|
@ -1,27 +0,0 @@
|
|||
import template from './index.html';
|
||||
import {module} from '../module';
|
||||
|
||||
class Controller {
|
||||
constructor($element, $state) {
|
||||
this.element = $element[0];
|
||||
this.$state = $state;
|
||||
this.note = {
|
||||
clientFk: $state.params.id,
|
||||
text: null
|
||||
};
|
||||
}
|
||||
onSubmit() {
|
||||
this.element.querySelector('vn-watcher').$ctrl.submit().then(
|
||||
() => this.$state.go('clientCard.notes')
|
||||
);
|
||||
}
|
||||
}
|
||||
Controller.$inject = ['$element', '$state'];
|
||||
|
||||
export const NAME = 'vnNewNote';
|
||||
export const COMPONENT = {
|
||||
template: template,
|
||||
controllerAs: 'newNote',
|
||||
controller: Controller
|
||||
};
|
||||
module.component(NAME, COMPONENT);
|
|
@ -1,17 +0,0 @@
|
|||
<vn-card ng-show="observation.observations.length" pad-medium>
|
||||
<vn-vertical pad-large>
|
||||
<vn-title>Notas</vn-title>
|
||||
<vn-horizontal ng-repeat="n in observation.observations" margin-small-bottom style="align-items: center;">
|
||||
<vn-auto style="border-radius: .3em;" class="pad-small border-solid">
|
||||
<div class="notes-date">{{n.created | date:'dd/MM/yyyy HH:mm'}}</div>
|
||||
<div class="notes-date">{{n.employee.name}}</div>
|
||||
<div>{{n.text}}</div>
|
||||
</vn-auto>
|
||||
</vn-horizontal>
|
||||
</vn-vertical>
|
||||
</vn-card>
|
||||
<vn-float-button
|
||||
fixed-bottom-right
|
||||
ng-click="observation.newObservation()"
|
||||
icon="add">
|
||||
</vn-float-button>
|
|
@ -1,34 +0,0 @@
|
|||
import './style.css';
|
||||
import template from './index.html';
|
||||
import {module} from '../module';
|
||||
|
||||
export const NAME = 'vnClientNotes';
|
||||
export const COMPONENT = {
|
||||
template: template,
|
||||
controllerAs: 'observation',
|
||||
bindings: {
|
||||
client: '<'
|
||||
},
|
||||
controller: function($http, $state) {
|
||||
this.$onChanges = function(changes) {
|
||||
if (this.client) {
|
||||
this.getObservation(this.client.id);
|
||||
}
|
||||
};
|
||||
|
||||
this.getObservation = function(clientId) {
|
||||
let json = JSON.stringify({where: {clientFk: this.client.id}, order: 'created DESC'});
|
||||
$http.get(`/client/api/clientObservations?filter=${json}`).then(
|
||||
json => {
|
||||
this.observations = json.data;
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
this.newObservation = () => {
|
||||
$state.go("clientCard.notes.create", {id: this.client.id});
|
||||
};
|
||||
}
|
||||
};
|
||||
COMPONENT.controller.$inject = ['$http', '$state'];
|
||||
module.component(NAME, COMPONENT);
|
|
@ -1,26 +0,0 @@
|
|||
<div pad-large style="min-width: 30em;" ng-show="$ctrl.formVisibility">
|
||||
<form name="form" ng-submit="form.$valid && $ctrl.onSearch()" ng-keyup="$ctrl.getKeyPressed($event)">
|
||||
<vn-horizontal>
|
||||
<vn-textfield vn-one label="Id Cliente" model="$ctrl.filter.id" vn-focus></vn-textfield>
|
||||
<vn-textfield vn-one label="NIF/CIF" model="$ctrl.filter.fi"></vn-textfield>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-textfield vn-one label="Nombre" model="$ctrl.filter.name"></vn-textfield>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-textfield vn-one label="Razon Social" model="$ctrl.filter.socialName"></vn-textfield>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-textfield vn-one label="Población" model="$ctrl.filter.city"></vn-textfield>
|
||||
<vn-textfield vn-one label="Código Postal" model="$ctrl.filter.postcode"></vn-textfield>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-textfield vn-one label="Email" model="$ctrl.filter.email"></vn-textfield>
|
||||
<vn-textfield vn-one label="Teléfono" model="$ctrl.filter.phone"></vn-textfield>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal margin-large-top>
|
||||
<vn-submit label="Search"></vn-submit>
|
||||
</vn-horizontal>
|
||||
</form>
|
||||
</div>
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
import {module} from '../module';
|
||||
|
||||
export const NAME = 'vnClientSearchPanel';
|
||||
export const COMPONENT = {
|
||||
template: require('./index.html'),
|
||||
controller: function($scope, $window) {
|
||||
this.filter = {id: null, fi: null, name: null, socialName: null, city: null, postcode: null, email: null, phone: null};
|
||||
this.formVisibility = true;
|
||||
this.onSearch = () => {
|
||||
this.setStorageValue();
|
||||
this.onSubmit(this.filter);
|
||||
};
|
||||
this.getKeyPressed = function(event) {
|
||||
if (event.which === 27)
|
||||
this.formVisibility = false;
|
||||
};
|
||||
this.$onChanges = () => {
|
||||
var value = JSON.parse($window.sessionStorage.getItem('filter'));
|
||||
if (value !== undefined)
|
||||
this.filter = value;
|
||||
};
|
||||
this.setStorageValue = () => {
|
||||
$window.sessionStorage.setItem('filter', JSON.stringify(this.filter));
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
module.component(NAME, COMPONENT);
|
|
@ -1,42 +0,0 @@
|
|||
<vn-watcher
|
||||
vn-id="watcher"
|
||||
url="/client/api/Accounts"
|
||||
id-field="id"
|
||||
data="$ctrl.client.account"
|
||||
to="$ctrl.account"
|
||||
form="form">
|
||||
</vn-watcher>
|
||||
<form name="form" ng-submit="watcher.submit()" pad-medium>
|
||||
<vn-card>
|
||||
<vn-vertical pad-large>
|
||||
<vn-title>Web access</vn-title>
|
||||
<vn-check label="Acceso Web" field="$ctrl.account.active"></vn-check>
|
||||
<vn-textfield label="Usuario" class="margin-medium-top" field="$ctrl.account.name" vn-focus></vn-textfield>
|
||||
</vn-vertical>
|
||||
</vn-card>
|
||||
<vn-button-bar>
|
||||
<vn-submit label="Guardar"></vn-submit>
|
||||
<vn-button label="Cambiar contraseña" vn-dialog="change-pass"></vn-button>
|
||||
</vn-button-bar>
|
||||
</form>
|
||||
<vn-dialog
|
||||
vn-id="change-pass"
|
||||
on-open="$ctrl.onPassOpen()"
|
||||
on-response="$ctrl.onPassChange(response)">
|
||||
<tpl-body>
|
||||
<vn-textfield
|
||||
type="password"
|
||||
label="New password"
|
||||
model="$ctrl.newPassword">
|
||||
</vn-textfield>
|
||||
<vn-textfield
|
||||
type="password"
|
||||
label="Repeat password"
|
||||
model="$ctrl.repeatPassword">
|
||||
</vn-textfield>
|
||||
</tpl-body>
|
||||
<tpl-buttons>
|
||||
<button response="CANCEL" translate>Cancel</button>
|
||||
<button response="ACCEPT" translate>Change password</button>
|
||||
</tpl-buttons>
|
||||
</vn-dialog>
|
|
@ -1,48 +0,0 @@
|
|||
import {module} from '../module';
|
||||
|
||||
class Controller {
|
||||
constructor($scope, $http, vnAppLogger) {
|
||||
this.$scope = $scope;
|
||||
this.$http = $http;
|
||||
this.vnAppLogger = vnAppLogger;
|
||||
}
|
||||
$onChanges() {
|
||||
if(this.client)
|
||||
this.account = this.client.account;
|
||||
}
|
||||
onPassOpen() {
|
||||
this.newPassword = '';
|
||||
this.repeatPassword = '';
|
||||
this.$scope.$apply();
|
||||
}
|
||||
onPassChange(response) {
|
||||
if(response == 'ACCEPT')
|
||||
try {
|
||||
if(!this.newPassword)
|
||||
throw new Error(`Passwords can't be empty`);
|
||||
if(this.newPassword != this.repeatPassword)
|
||||
throw new Error(`Passwords don't match`);
|
||||
|
||||
let account = {
|
||||
password: this.newPassword
|
||||
};
|
||||
|
||||
this.$http.put(`/client/api/Accounts/${this.client.id}`, account);
|
||||
}
|
||||
catch(e) {
|
||||
this.vnAppLogger.showError(e.message);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Controller.$inject = ['$scope', '$http', 'vnAppLogger'];
|
||||
|
||||
module.component('vnClientWebAccess', {
|
||||
template: require('./index.html'),
|
||||
bindings: {
|
||||
client: '<'
|
||||
},
|
||||
controller: Controller
|
||||
});
|
|
@ -1,10 +0,0 @@
|
|||
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
|
||||
<input type="text"
|
||||
class="mdl-textfield__input"
|
||||
ng-keydown="$ctrl.onKeydown($event)"
|
||||
ng-click="$ctrl.onClick($event)"
|
||||
ng-keyup="$ctrl.onKeyup($event)"
|
||||
ng-focus="$ctrl.onFocus($event)"
|
||||
ng-blur="$ctrl.onBlur($event)"/>
|
||||
<label class="mdl-textfield__label">{{$ctrl.label | translate}}</label>
|
||||
</div>
|
|
@ -1,418 +0,0 @@
|
|||
import {module} from '../module';
|
||||
import Component from '../lib/component';
|
||||
import './style.scss';
|
||||
|
||||
/**
|
||||
* Combobox like component with search and partial data loading features.
|
||||
*/
|
||||
export default class Autocomplete extends Component {
|
||||
constructor($element, $scope, $http, vnPopover, $transclude) {
|
||||
super($element);
|
||||
this.input = $element[0].querySelector('input');
|
||||
this.item = null;
|
||||
this.data = null;
|
||||
this.popover = null;
|
||||
this.displayData = null;
|
||||
this.timeoutId = null;
|
||||
this.lastSearch = null;
|
||||
this.lastRequest = null;
|
||||
this.currentRequest = null;
|
||||
this.moreData = false;
|
||||
this.activeOption = -1;
|
||||
this.locked = false;
|
||||
this.$http = $http;
|
||||
this.$scope = $scope;
|
||||
this.vnPopover = vnPopover;
|
||||
this.$transclude = $transclude;
|
||||
this.scopes = null;
|
||||
|
||||
Object.assign(this, {
|
||||
maxRows: 10,
|
||||
requestDelay: 350,
|
||||
showField: 'name',
|
||||
valueField: 'id',
|
||||
itemAs: 'i'
|
||||
});
|
||||
|
||||
componentHandler.upgradeElement($element[0].firstChild);
|
||||
}
|
||||
set field(value) {
|
||||
this.locked = true;
|
||||
this.setValue(value);
|
||||
this.locked = false;
|
||||
}
|
||||
get field() {
|
||||
return this.value;
|
||||
}
|
||||
set initialData(value) {
|
||||
if (value) {
|
||||
if (!this.data)
|
||||
this.data = [];
|
||||
this.data.push(value);
|
||||
}
|
||||
}
|
||||
set selectFields(value) {
|
||||
this._selectFields = [];
|
||||
|
||||
if (!value)
|
||||
return;
|
||||
|
||||
let res = value.split(',');
|
||||
for (let i of res)
|
||||
this._selectFields.push(i.trim());
|
||||
}
|
||||
mdlUpdate() {
|
||||
let mdlField = this.element.firstChild.MaterialTextfield;
|
||||
if (mdlField)
|
||||
mdlField.updateClasses_();
|
||||
}
|
||||
loadData(textFilter) {
|
||||
textFilter = textFilter ? textFilter : '';
|
||||
|
||||
if (this.lastSearch === textFilter) {
|
||||
this.showPopoverIfFocus();
|
||||
return;
|
||||
}
|
||||
|
||||
this.lastSearch = textFilter;
|
||||
|
||||
let lastRequest = this.lastRequest;
|
||||
let requestWillSame = lastRequest !== null
|
||||
&& !this.moreData
|
||||
&& textFilter.substr(0, lastRequest.length) === lastRequest;
|
||||
|
||||
if (requestWillSame)
|
||||
this.localFilter(textFilter);
|
||||
else
|
||||
this.requestData(textFilter, false);
|
||||
}
|
||||
getRequestFields() {
|
||||
let fields = {};
|
||||
fields[this.valueField] = true;
|
||||
fields[this.showField] = true;
|
||||
|
||||
if (this._selectFields)
|
||||
for (let field of this._selectFields)
|
||||
fields[field] = true;
|
||||
|
||||
return fields;
|
||||
}
|
||||
requestData(textFilter, append) {
|
||||
let where = {};
|
||||
let skip = 0;
|
||||
|
||||
if (textFilter)
|
||||
where[this.showField] = {regexp: textFilter};
|
||||
if (append && this.data)
|
||||
skip = this.data.length;
|
||||
|
||||
let filter = {
|
||||
fields: this.getRequestFields(),
|
||||
where: where,
|
||||
order: `${this.showField} ASC`,
|
||||
skip: skip,
|
||||
limit: this.maxRows
|
||||
};
|
||||
|
||||
this.lastRequest = textFilter ? textFilter : '';
|
||||
let json = JSON.stringify(filter);
|
||||
|
||||
if (this.currentRequest)
|
||||
this.currentRequest.resolve();
|
||||
|
||||
this.currentRequest = this.$http.get(`${this.url}?filter=${json}`);
|
||||
this.currentRequest.then(
|
||||
json => this.onRequest(json.data, append),
|
||||
json => this.onRequest([])
|
||||
);
|
||||
}
|
||||
onRequest(data, append) {
|
||||
this.currentRequest = null;
|
||||
this.moreData = data.length >= this.maxRows;
|
||||
|
||||
if (!append || !this.data)
|
||||
this.data = data;
|
||||
else
|
||||
this.data = this.data.concat(data);
|
||||
|
||||
this.setDisplayData(this.data);
|
||||
}
|
||||
localFilter(textFilter) {
|
||||
let regex = new RegExp(textFilter, 'i');
|
||||
let data = this.data.filter(item => {
|
||||
return regex.test(item[this.showField]);
|
||||
});
|
||||
this.setDisplayData(data);
|
||||
}
|
||||
setDisplayData(data) {
|
||||
this.displayData = data;
|
||||
this.showPopoverIfFocus();
|
||||
}
|
||||
showPopoverIfFocus() {
|
||||
if (this.hasFocus)
|
||||
this.showPopover();
|
||||
}
|
||||
destroyScopes() {
|
||||
if (this.scopes)
|
||||
for (let scope of this.scopes)
|
||||
scope.$destroy();
|
||||
}
|
||||
showPopover() {
|
||||
let data = this.displayData;
|
||||
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
let fragment = this.document.createDocumentFragment();
|
||||
this.destroyScopes();
|
||||
this.scopes = [];
|
||||
|
||||
let hasTemplate = this.$transclude.isSlotFilled('tplItem');
|
||||
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
let li = this.document.createElement('li');
|
||||
fragment.appendChild(li);
|
||||
|
||||
if (hasTemplate) {
|
||||
this.$transclude((clone, scope) => {
|
||||
scope[this.itemAs] = data[i];
|
||||
li.appendChild(clone[0]);
|
||||
this.scopes[i] = scope;
|
||||
}, null, 'tplItem');
|
||||
} else {
|
||||
let text = this.document.createTextNode(data[i][this.showField]);
|
||||
li.appendChild(text);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.moreData) {
|
||||
let li = this.document.createElement('li');
|
||||
li.appendChild(this.document.createTextNode('Load more'));
|
||||
li.className = 'load-more';
|
||||
fragment.appendChild(li);
|
||||
}
|
||||
|
||||
if (this.popover) {
|
||||
this.popover.innerHTML = '';
|
||||
this.popover.appendChild(fragment);
|
||||
} else {
|
||||
let popover = this.document.createElement('ul');
|
||||
popover.addEventListener('click',
|
||||
e => this.onPopoverClick(e));
|
||||
popover.addEventListener('mousedown',
|
||||
e => this.onPopoverMousedown(e));
|
||||
popover.className = 'vn-autocomplete';
|
||||
popover.appendChild(fragment);
|
||||
this.vnPopover.show(popover, this.input);
|
||||
this.popover = popover;
|
||||
}
|
||||
}
|
||||
hidePopover() {
|
||||
if (!this.popover) return;
|
||||
this.activeOption = -1;
|
||||
this.vnPopover.hide();
|
||||
this.destroyScopes();
|
||||
this.popover = null;
|
||||
}
|
||||
selectPopoverOption(index) {
|
||||
if (!this.popover || index === -1) return;
|
||||
if (index < this.displayData.length) {
|
||||
this.selectOptionByDataIndex(this.displayData, index);
|
||||
this.hidePopover();
|
||||
} else
|
||||
this.requestData(this.lastRequest, true);
|
||||
}
|
||||
onPopoverClick(event) {
|
||||
let target = event.target;
|
||||
let childs = this.popover.childNodes;
|
||||
|
||||
if (target === this.popover)
|
||||
return;
|
||||
|
||||
while (target.parentNode !== this.popover)
|
||||
target = target.parentNode;
|
||||
|
||||
for (let i = 0; i < childs.length; i++)
|
||||
if (childs[i] === target) {
|
||||
this.selectPopoverOption(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
onPopoverMousedown(event) {
|
||||
// Prevents input from loosing focus
|
||||
event.preventDefault();
|
||||
}
|
||||
onClick(event) {
|
||||
if (!this.popover)
|
||||
this.showPopover();
|
||||
}
|
||||
onFocus() {
|
||||
this.hasFocus = true;
|
||||
this.input.select();
|
||||
|
||||
this.loadData();
|
||||
}
|
||||
onBlur() {
|
||||
this.hasFocus = false;
|
||||
this.restoreShowValue();
|
||||
this.hidePopover();
|
||||
}
|
||||
onKeydown(event) {
|
||||
switch (event.keyCode) {
|
||||
case 13: // Enter
|
||||
this.selectPopoverOption(this.activeOption);
|
||||
break;
|
||||
case 27: // Escape
|
||||
this.restoreShowValue();
|
||||
this.input.select();
|
||||
break;
|
||||
case 38: // Arrow up
|
||||
this.activateOption(this.activeOption - 1);
|
||||
break;
|
||||
case 40: // Arrow down
|
||||
this.activateOption(this.activeOption + 1);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
event.preventDefault();
|
||||
}
|
||||
onKeyup(event) {
|
||||
if (!this.isKeycodePrintable(event.keyCode)) return;
|
||||
if (this.timeoutId) clearTimeout(this.timeoutId);
|
||||
this.timeoutId = setTimeout(() => this.onTimeout(), this.requestDelay);
|
||||
}
|
||||
onTimeout() {
|
||||
this.loadData(this.input.value);
|
||||
this.timeoutId = null;
|
||||
}
|
||||
isKeycodePrintable(keyCode) {
|
||||
return keyCode === 32 // Spacebar
|
||||
|| keyCode === 8 // Backspace
|
||||
|| (keyCode > 47 && keyCode < 58) // Numbers
|
||||
|| (keyCode > 64 && keyCode < 91) // Letters
|
||||
|| (keyCode > 95 && keyCode < 112) // Numpad
|
||||
|| (keyCode > 185 && keyCode < 193) // ;=,-./`
|
||||
|| (keyCode > 218 && keyCode < 223); // [\]'
|
||||
}
|
||||
restoreShowValue() {
|
||||
this.putItem(this.item);
|
||||
}
|
||||
requestItem() {
|
||||
if (!this.value) return;
|
||||
|
||||
let where = {};
|
||||
where[this.valueField] = this.value;
|
||||
|
||||
let filter = {
|
||||
fields: this.getRequestFields(),
|
||||
where: where
|
||||
};
|
||||
|
||||
let json = JSON.stringify(filter);
|
||||
|
||||
this.$http.get(`${this.url}?filter=${json}`).then(
|
||||
json => this.onItemRequest(json.data),
|
||||
json => this.onItemRequest(null)
|
||||
);
|
||||
}
|
||||
onItemRequest(data) {
|
||||
if (data && data.length > 0)
|
||||
this.showItem(data[0]);
|
||||
else
|
||||
this.showItem(null);
|
||||
}
|
||||
activateOption(index) {
|
||||
if (!this.popover)
|
||||
this.showPopover();
|
||||
|
||||
let popover = this.popover;
|
||||
let childs = popover.childNodes;
|
||||
let len = this.displayData.length;
|
||||
|
||||
if (this.activeOption >= 0)
|
||||
childs[this.activeOption].className = '';
|
||||
|
||||
if (index >= len)
|
||||
index = 0;
|
||||
else if (index < 0)
|
||||
index = len - 1;
|
||||
|
||||
if (index >= 0) {
|
||||
let opt = childs[index];
|
||||
let top = popover.scrollTop;
|
||||
let height = popover.clientHeight;
|
||||
|
||||
if (opt.offsetTop + opt.offsetHeight > top + height)
|
||||
top = opt.offsetTop + opt.offsetHeight - height;
|
||||
else if (opt.offsetTop < top)
|
||||
top = opt.offsetTop;
|
||||
|
||||
opt.className = 'active';
|
||||
popover.scrollTop = top;
|
||||
}
|
||||
|
||||
this.activeOption = index;
|
||||
}
|
||||
setValue(value) {
|
||||
this.value = value;
|
||||
|
||||
if (value) {
|
||||
let data = this.data;
|
||||
|
||||
if (data)
|
||||
for (let i = 0; i < data.length; i++)
|
||||
if (data[i][this.valueField] == value) {
|
||||
this.putItem(data[i]);
|
||||
return;
|
||||
}
|
||||
|
||||
this.requestItem();
|
||||
} else
|
||||
this.putItem(null);
|
||||
}
|
||||
selectOptionByIndex(index) {
|
||||
this.selectOptionByDataIndex(this.data, index);
|
||||
}
|
||||
selectOptionByDataIndex(data, index) {
|
||||
if (data && index >= 0 && index < data.length)
|
||||
this.putItem(data[index]);
|
||||
else
|
||||
this.putItem(null);
|
||||
}
|
||||
putItem(item) {
|
||||
this.showItem(item);
|
||||
let value = item ? item[this.valueField] : undefined;
|
||||
|
||||
if (!this.locked)
|
||||
this.value = value;
|
||||
}
|
||||
showItem(item) {
|
||||
this.input.value = item ? item[this.showField] : '';
|
||||
this.item = item;
|
||||
this.mdlUpdate();
|
||||
}
|
||||
$onDestroy() {
|
||||
this.destroyScopes();
|
||||
}
|
||||
}
|
||||
Autocomplete.$inject = ['$element', '$scope', '$http', 'vnPopover', '$transclude'];
|
||||
|
||||
module.component('vnAutocomplete', {
|
||||
template: require('./index.html'),
|
||||
bindings: {
|
||||
url: '@',
|
||||
showField: '@?',
|
||||
valueField: '@?',
|
||||
selectFields: '@?',
|
||||
initialData: '<?',
|
||||
itemAs: '@?',
|
||||
field: '=',
|
||||
label: '@'
|
||||
},
|
||||
transclude: {
|
||||
tplItem: '?tplItem'
|
||||
},
|
||||
controller: Autocomplete
|
||||
});
|
|
@ -1,23 +0,0 @@
|
|||
<div ng-mousedown="$ctrl.onDialogMouseDown($event)">
|
||||
<button ng-click="$ctrl.hide()" class="close" translate-attr="{title: 'Close'}">
|
||||
<vn-icon vn-one icon="clear" style="color:black"></vn-icon>
|
||||
</button>
|
||||
<form>
|
||||
<div>
|
||||
<tpl-body>
|
||||
<h6 class="dialog-title" translate>
|
||||
{{$ctrl.question}}
|
||||
</h6>
|
||||
<h6 translate>
|
||||
{{$ctrl.message}}
|
||||
</h6>
|
||||
</tpl-body>
|
||||
</div>
|
||||
<div class="button-bar" ng-click="$ctrl.onButtonClick($event)">
|
||||
<tpl-buttons>
|
||||
<button response="CANCEL" translate>Cancel</button>
|
||||
<button response="ACCEPT" translate>Accept</button>
|
||||
</tpl-buttons>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
|
@ -1,16 +0,0 @@
|
|||
import {module} from '../module';
|
||||
import Dialog from '../dialog/index';
|
||||
import './style.css';
|
||||
|
||||
export default class Confirm extends Dialog {}
|
||||
Dialog.$inject = ['$element'];
|
||||
|
||||
module.component('vnConfirm', {
|
||||
template: require('./index.html'),
|
||||
bindings: {
|
||||
onResponse: '&',
|
||||
question: '@',
|
||||
message: '@'
|
||||
},
|
||||
controller: Confirm
|
||||
});
|
|
@ -1,13 +0,0 @@
|
|||
<div ng-mousedown="$ctrl.onDialogMouseDown($event)">
|
||||
<button ng-click="$ctrl.hide()" class="close" translate-attr="{title: 'Close'}">
|
||||
<vn-icon vn-one icon="clear" style="color:black"></vn-icon>
|
||||
</button>
|
||||
<form>
|
||||
<div ng-transclude="tplBody"></div>
|
||||
<div
|
||||
ng-transclude="tplButtons"
|
||||
class="button-bar"
|
||||
ng-click="$ctrl.onButtonClick($event)">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
|
@ -1,111 +0,0 @@
|
|||
import {module} from '../module';
|
||||
import Component from '../lib/component';
|
||||
import './style.scss';
|
||||
|
||||
/**
|
||||
* Dialog component.
|
||||
*/
|
||||
export default class Dialog extends Component {
|
||||
/**
|
||||
* Contructor.
|
||||
*/
|
||||
constructor($element) {
|
||||
super($element);
|
||||
$element.addClass('vn-dialog');
|
||||
this.dialog = $element[0].firstChild;
|
||||
this.element.addEventListener('mousedown',
|
||||
event => this.onBackgroundMouseDown(event));
|
||||
}
|
||||
/**
|
||||
* Displays the dialog to the user.
|
||||
*/
|
||||
show() {
|
||||
let style = this.dialog.style;
|
||||
let screenMargin = 20;
|
||||
|
||||
let window = this.window;
|
||||
let innerWidth = window.innerWidth;
|
||||
let innerHeight = window.innerHeight;
|
||||
let width = this.dialog.offsetWidth;
|
||||
let height = this.dialog.offsetHeight;
|
||||
|
||||
if (width + screenMargin > innerWidth) {
|
||||
width = innerWidth - dblMargin;
|
||||
style.width = width + 'px';
|
||||
}
|
||||
if (height + screenMargin > innerHeight) {
|
||||
height = innerHeight - dblMargin;
|
||||
style.height = height + 'px';
|
||||
}
|
||||
|
||||
this.keypressHandler =
|
||||
event => this.onKeypress(event);
|
||||
this.document.addEventListener('keypress',
|
||||
this.keypressHandler);
|
||||
this.element.style.display = 'block';
|
||||
|
||||
if (this.onOpen)
|
||||
this.onOpen();
|
||||
}
|
||||
/**
|
||||
* Hides the dialog calling the response handler.
|
||||
*/
|
||||
hide() {
|
||||
this.fireResponse();
|
||||
this.realHide();
|
||||
}
|
||||
/**
|
||||
* Calls the response handler.
|
||||
*/
|
||||
fireResponse(response) {
|
||||
let cancel = false;
|
||||
if (this.onResponse)
|
||||
cancel = this.onResponse({response: response});
|
||||
return cancel;
|
||||
}
|
||||
realHide() {
|
||||
this.element.style.display = 'none';
|
||||
this.document.removeEventListener('keypress',
|
||||
this.keypressHandler);
|
||||
this.lastEvent = null;
|
||||
}
|
||||
onButtonClick(event) {
|
||||
let buttonBar = this.element.querySelector('.button-bar');
|
||||
let buttons = buttonBar.querySelector('tpl-buttons');
|
||||
let node = event.target;
|
||||
|
||||
while (node.parentNode != buttons) {
|
||||
if (node == buttonBar) return;
|
||||
node = node.parentNode;
|
||||
}
|
||||
|
||||
let response = node.getAttribute('response');
|
||||
let cancel = this.fireResponse(response);
|
||||
if (cancel !== false) this.realHide();
|
||||
}
|
||||
onDialogMouseDown(event) {
|
||||
this.lastEvent = event;
|
||||
}
|
||||
onBackgroundMouseDown(event) {
|
||||
if (event != this.lastEvent)
|
||||
this.hide();
|
||||
}
|
||||
onKeypress(event) {
|
||||
if (event.keyCode == 27) // Esc
|
||||
this.hide();
|
||||
}
|
||||
}
|
||||
Dialog.$inject = ['$element'];
|
||||
|
||||
module.component('vnDialog', {
|
||||
template: require('./index.html'),
|
||||
transclude: {
|
||||
tplBody: 'tplBody',
|
||||
tplButtons: 'tplButtons'
|
||||
},
|
||||
bindings: {
|
||||
onOpen: '&',
|
||||
onResponse: '&'
|
||||
},
|
||||
controller: Dialog
|
||||
});
|
|
@ -1,19 +0,0 @@
|
|||
import {module} from '../module';
|
||||
import './index.mdl';
|
||||
import './style.css';
|
||||
import * as resolveFactory from '../lib/resolveDefaultComponents';
|
||||
|
||||
const _NAME = 'icon';
|
||||
export const NAME = 'vnIcon';
|
||||
|
||||
export function directive(resolver) {
|
||||
return {
|
||||
restrict: 'E',
|
||||
template: function(_, attrs) {
|
||||
return resolver.getTemplate(_NAME, attrs);
|
||||
}
|
||||
};
|
||||
}
|
||||
directive.$inject = [resolveFactory.NAME];
|
||||
|
||||
module.directive(NAME, directive);
|
|
@ -1 +0,0 @@
|
|||
<i class="material-icons">*[icon]*</i>
|
|
@ -1,12 +0,0 @@
|
|||
import {module} from '../module';
|
||||
import template from './index.mdl.html';
|
||||
|
||||
export const NAME = 'vnIconMdlFactory';
|
||||
export function factory() {
|
||||
return {
|
||||
template: template,
|
||||
default: {}
|
||||
}
|
||||
}
|
||||
|
||||
module.factory(NAME, factory);
|
|
@ -1,10 +0,0 @@
|
|||
<paging
|
||||
page="$ctrl.currentPage"
|
||||
page-size="$ctrl.numPerPage"
|
||||
total="$ctrl.numItems"
|
||||
show-prev-next="true"
|
||||
show-first-last="false"
|
||||
active-class="active"
|
||||
ng-click="$ctrl.figureOutToDisplay()"
|
||||
paging-action="$ctrl.onPageChange(page)">
|
||||
</paging>
|
|
@ -1,46 +0,0 @@
|
|||
import {module} from '../module';
|
||||
import './style.scss';
|
||||
|
||||
export default class Paging {
|
||||
get numPages() {
|
||||
return Math.ceil(this.numItems / this.numPerPage);
|
||||
}
|
||||
constructor($http, $scope) {
|
||||
this.$http = $http;
|
||||
this.$scope = $scope;
|
||||
this.where = this.filter;
|
||||
this.numPerPage = null;
|
||||
this.numItems = 0;
|
||||
$scope.$watch('$ctrl.index.model.length', () => this.onModelUpdated());
|
||||
}
|
||||
$onChanges(changes) {
|
||||
if (!this.index) return;
|
||||
this.numPerPage = this.index.filter.size;
|
||||
if(changes.total)
|
||||
this.numItems = changes.total.currentValue;
|
||||
}
|
||||
onModelUpdated() {
|
||||
let index = this.index;
|
||||
let filter = index.filter;
|
||||
|
||||
if (filter.page >= this.numPages
|
||||
&& index.model.length >= this.numPerPage)
|
||||
this.numItems = filter.page * filter.size + 1;
|
||||
}
|
||||
onPageChange(page) {
|
||||
this.index.filter.page = page;
|
||||
this.index.accept();
|
||||
}
|
||||
}
|
||||
Paging.$inject = ['$http', '$scope'];
|
||||
|
||||
export const NAME = 'vnPaging';
|
||||
export const COMPONENT = {
|
||||
template: require('./index.html'),
|
||||
bindings: {
|
||||
index: '<',
|
||||
total: '<'
|
||||
},
|
||||
controller: Paging
|
||||
};
|
||||
module.component(NAME, COMPONENT);
|
|
@ -1,98 +0,0 @@
|
|||
import {module} from '../module';
|
||||
import './style.css';
|
||||
|
||||
directive.$inject = ['vnPopover'];
|
||||
export function directive(popover) {
|
||||
return {
|
||||
restrict: 'A',
|
||||
link: function($scope, $element, $attrs) {
|
||||
$element.on('click', function(event) {
|
||||
popover.showComponent($attrs.vnDialog, $scope, $element);
|
||||
event.preventDefault();
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
module.directive('vnPopover', directive);
|
||||
|
||||
export class Popover {
|
||||
constructor($document, $compile) {
|
||||
this.document = $document[0];
|
||||
this.$compile = $compile;
|
||||
}
|
||||
show(childElement, parent) {
|
||||
let popover = this.document.createElement('div');
|
||||
popover.className = 'vn-popover';
|
||||
popover.addEventListener('mousedown',
|
||||
event => this.onPopoverMouseDown(event));
|
||||
popover.appendChild(childElement);
|
||||
this.popover = popover;
|
||||
|
||||
let style = popover.style;
|
||||
|
||||
let spacing = 0;
|
||||
let screenMargin = 20;
|
||||
let dblMargin = screenMargin * 2;
|
||||
|
||||
let width = popover.offsetWidth;
|
||||
let height = popover.offsetHeight;
|
||||
let innerWidth = window.innerWidth;
|
||||
let innerHeight = window.innerHeight;
|
||||
|
||||
if (width + dblMargin > innerWidth) {
|
||||
width = innerWidth - dblMargin;
|
||||
style.width = width + 'px';
|
||||
}
|
||||
if (height + dblMargin > innerHeight) {
|
||||
height = innerHeight - dblMargin;
|
||||
style.height = height + 'px';
|
||||
}
|
||||
|
||||
if (parent) {
|
||||
let parentNode = parent;
|
||||
let rect = parentNode.getBoundingClientRect();
|
||||
let left = rect.left;
|
||||
let top = rect.top + spacing + parentNode.offsetHeight;
|
||||
|
||||
if (left + width > innerWidth)
|
||||
left -= (left + width) - innerWidth + margin;
|
||||
if (top + height > innerHeight)
|
||||
top -= height + parentNode.offsetHeight + spacing * 2;
|
||||
|
||||
if (left < 0)
|
||||
left = screenMargin;
|
||||
if (top < 0)
|
||||
top = screenMargin;
|
||||
|
||||
style.top = (top) + 'px';
|
||||
style.left = (left) + 'px';
|
||||
style.minWidth = (rect.width) + 'px';
|
||||
}
|
||||
|
||||
this.document.body.appendChild(popover);
|
||||
this.docMouseDownHandler = event => this.onDocMouseDown(event);
|
||||
this.document.addEventListener('mousedown', this.docMouseDownHandler);
|
||||
}
|
||||
showComponent(childComponent, $scope, parent) {
|
||||
let childElement = this.document.createElement(childComponent);
|
||||
this.$compile(childElement)($scope);
|
||||
this.show(childElement, parent);
|
||||
}
|
||||
hide() {
|
||||
if (!this.popover) return;
|
||||
this.document.removeEventListener('mousedown', this.docMouseDownHandler);
|
||||
this.document.body.removeChild(this.popover);
|
||||
this.popover = null;
|
||||
this.lastEvent = null;
|
||||
this.docMouseDownHandler = null;
|
||||
}
|
||||
onDocMouseDown(event) {
|
||||
if (event != this.lastEvent)
|
||||
this.hide();
|
||||
}
|
||||
onPopoverMouseDown(event) {
|
||||
this.lastEvent = event;
|
||||
}
|
||||
}
|
||||
Popover.$inject = ['$document', '$compile'];
|
||||
module.service('vnPopover', Popover);
|
|
@ -1,4 +0,0 @@
|
|||
<div class="mdl-js-snackbar mdl-snackbar" style="z-index: 200;">
|
||||
<div class="mdl-snackbar__text"></div>
|
||||
<button class="mdl-snackbar__action" type="button"></button>
|
||||
</div>
|
|
@ -1,25 +0,0 @@
|
|||
import {module} from '../module';
|
||||
|
||||
/**
|
||||
* A simple component to show non-obstructive notifications to the user.
|
||||
*/
|
||||
export default class Controller {
|
||||
constructor($element) {
|
||||
this.snackbar = $element[0].firstChild;
|
||||
componentHandler.upgradeElement(this.snackbar);
|
||||
}
|
||||
/**
|
||||
* Shows a notification.
|
||||
*
|
||||
* @param {Object} data The message data
|
||||
*/
|
||||
show(data) {
|
||||
this.snackbar.MaterialSnackbar.showSnackbar(data);
|
||||
}
|
||||
}
|
||||
Controller.$inject = ['$element'];
|
||||
|
||||
module.component('vnSnackbar', {
|
||||
template: require('./index.html'),
|
||||
controller: Controller
|
||||
});
|
|
@ -1,2 +0,0 @@
|
|||
<div class="mdl-spinner mdl-spinner--single-color mdl-js-spinner">
|
||||
</div>
|
|
@ -1,58 +0,0 @@
|
|||
import {module} from '../module';
|
||||
import Component from '../lib/component';
|
||||
import './style.css';
|
||||
|
||||
/**
|
||||
* A spinner to inform the user about loading process.
|
||||
*/
|
||||
export default class Spinner extends Component {
|
||||
constructor($element, $scope) {
|
||||
super($element);
|
||||
this._enable = false;
|
||||
this.spinner = $element[0].firstChild;
|
||||
componentHandler.upgradeElement(this.spinner);
|
||||
}
|
||||
/**
|
||||
* Enables/disables the spinner.
|
||||
*
|
||||
* @param {Boolean} value %true to enable, %false to disable
|
||||
*/
|
||||
set enable(value) {
|
||||
if (value)
|
||||
this.start();
|
||||
else
|
||||
this.stop();
|
||||
}
|
||||
/**
|
||||
* Returns the current spinner state.
|
||||
*
|
||||
* @return {Boolean} %true if it's enabled, %false otherwise
|
||||
*/
|
||||
get enable() {
|
||||
return this._enable;
|
||||
}
|
||||
/**
|
||||
* Activates the spinner.
|
||||
*/
|
||||
start() {
|
||||
this.spinner.MaterialSpinner.start();
|
||||
this._enable = true;
|
||||
}
|
||||
/**
|
||||
* Deactivates the spinner.
|
||||
*/
|
||||
stop() {
|
||||
this.spinner.MaterialSpinner.stop();
|
||||
this._enable = false;
|
||||
}
|
||||
}
|
||||
Spinner.$inject = ['$element', '$scope'];
|
||||
|
||||
export const component = {
|
||||
template: require('./index.html'),
|
||||
bindings: {
|
||||
enable: '='
|
||||
},
|
||||
controller: Spinner
|
||||
};
|
||||
module.component('vnSpinner', component);
|
|
@ -1,2 +0,0 @@
|
|||
<h5 style="margin-top: 0;" class="margin-medium-bottom" ng-transclude>
|
||||
</h5>
|
|
@ -1,6 +0,0 @@
|
|||
import {module} from '../module';
|
||||
|
||||
module.component('vnSubtitle', {
|
||||
template: require('./index.html'),
|
||||
transclude: true
|
||||
});
|
|
@ -1,82 +0,0 @@
|
|||
import {module} from '../module';
|
||||
import Component from '../lib/component';
|
||||
import * as resolveFactory from '../lib/resolveDefaultComponents';
|
||||
import * as normalizerFactory from '../lib/inputAttrsNormalizer';
|
||||
import './style.scss';
|
||||
import './index.mdl';
|
||||
|
||||
export default class Textfield extends Component {
|
||||
constructor($element, $scope, $attrs) {
|
||||
super($element);
|
||||
|
||||
let input = this.input = this.element.querySelector('input');
|
||||
input.addEventListener('input',
|
||||
() => this.checkValue());
|
||||
input.addEventListener('focus',
|
||||
() => this.checkValue());
|
||||
input.addEventListener('blur',
|
||||
() => this.showClear(false));
|
||||
|
||||
let clearButton = this.element.querySelector('button');
|
||||
clearButton.addEventListener('click',
|
||||
() => this.onClearClick());
|
||||
clearButton.addEventListener('mousedown',
|
||||
event => event.preventDefault());
|
||||
|
||||
let div = this.element.firstChild;
|
||||
componentHandler.upgradeElement(div);
|
||||
}
|
||||
link($scope, $attrs) {
|
||||
let mdlTextField = this.element.firstChild.MaterialTextfield;
|
||||
mdlTextField.updateClasses_();
|
||||
|
||||
$scope.$watch($attrs.model,
|
||||
() => mdlTextField.updateClasses_());
|
||||
}
|
||||
onClearClick() {
|
||||
this.input.value = '';
|
||||
this.checkValue();
|
||||
|
||||
let event = this.document.createEvent('HTMLEvents');
|
||||
event.initEvent('change', false, true);
|
||||
this.input.dispatchEvent(event);
|
||||
}
|
||||
checkValue() {
|
||||
this.showClear(this.input.value);
|
||||
}
|
||||
showClear(show) {
|
||||
show = show && document.activeElement === this.input;
|
||||
let clearButton = this.element.querySelector('button');
|
||||
clearButton.style.visibility = show ? 'visible' : 'hidden';
|
||||
}
|
||||
/**
|
||||
* Selects the textfield.
|
||||
*/
|
||||
select() {
|
||||
this.input.select();
|
||||
}
|
||||
/**
|
||||
* Puts the focus on the textfield.
|
||||
*/
|
||||
focus() {
|
||||
this.input.focus();
|
||||
}
|
||||
}
|
||||
Textfield.$inject = ['$element', '$scope', '$attrs'];
|
||||
|
||||
directive.$inject = [resolveFactory.NAME, normalizerFactory.NAME];
|
||||
export function directive(resolve, normalizer) {
|
||||
return {
|
||||
restrict: 'E',
|
||||
template: function(_, attrs) {
|
||||
normalizer.normalize(attrs);
|
||||
return resolve.getTemplate('textfield', attrs);
|
||||
},
|
||||
link: function($scope, $element, $attrs, $ctrl) {
|
||||
$ctrl.link($scope, $attrs);
|
||||
},
|
||||
controller: Textfield
|
||||
};
|
||||
}
|
||||
|
||||
module.directive('vnTextfield', directive);
|
|
@ -1,18 +0,0 @@
|
|||
<div class="mdl-textfield mdl-js-textfield *[className]*">
|
||||
<input
|
||||
class="mdl-textfield__input"
|
||||
type="*[type]*"
|
||||
name="*[name]*"
|
||||
ng-model="*[model]*"
|
||||
vn-validation="*[rule]*"
|
||||
ng-disabled="*[disable]*"/>
|
||||
<button
|
||||
type="button"
|
||||
class="mdl-chip__action"
|
||||
tabindex="-1"
|
||||
translate-attr="{title: 'Clear'}"
|
||||
style="visibility: hidden">
|
||||
<i class="material-icons">clear</i>
|
||||
</button>
|
||||
<label class="mdl-textfield__label" translate>*[label]*</label>
|
||||
</div>
|
|
@ -1,16 +0,0 @@
|
|||
import {module} from '../module';
|
||||
|
||||
export const NAME = 'vnTextfieldMdlFactory';
|
||||
|
||||
export function factory() {
|
||||
return {
|
||||
template: require('./index.mdl.html'),
|
||||
default: {
|
||||
label: 'text',
|
||||
className: 'mdl-textfield--floating-label',
|
||||
type: 'text'
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
module.factory(NAME, factory);
|
|
@ -1,2 +0,0 @@
|
|||
<h3 style="margin-top: 0;" class="margin-medium-bottom" ng-transclude>
|
||||
</h3>
|
|
@ -1,6 +0,0 @@
|
|||
import {module} from '../module';
|
||||
|
||||
module.component('vnTitle', {
|
||||
template: require('./index.html'),
|
||||
transclude: true
|
||||
});
|
|
@ -1,6 +0,0 @@
|
|||
<vn-confirm
|
||||
vn-id="confirm"
|
||||
question="Are you sure exit without saving?"
|
||||
message="Unsaved changes will be lost"
|
||||
on-response="$ctrl.onConfirmResponse(response)">
|
||||
</vn-confirm>
|
|
@ -1,162 +0,0 @@
|
|||
import {module} from '../module';
|
||||
import Component from '../lib/component';
|
||||
import getModifiedData from '../lib/modified';
|
||||
import copyObject from '../lib/copy';
|
||||
import isEqual from '../lib/equals';
|
||||
|
||||
/**
|
||||
* Component that checks for changes on a specific model property and
|
||||
* asks the user to save or discard it when the state changes.
|
||||
* Also it can save the data to the server when the @url and @idField
|
||||
* properties are provided.
|
||||
*/
|
||||
export default class Watcher extends Component {
|
||||
constructor($element, $scope, $state, $transitions, $http, vnAppLogger, $translate) {
|
||||
super($element);
|
||||
this.$scope = $scope;
|
||||
this.$state = $state;
|
||||
this.$http = $http;
|
||||
this.$translate = $translate;
|
||||
this.vnAppLogger = vnAppLogger;
|
||||
|
||||
this.state = null;
|
||||
this.deregisterCallback = $transitions.onStart({},
|
||||
transition => this.callback(transition));
|
||||
this.copyData();
|
||||
}
|
||||
$onInit() {
|
||||
if (this.get) {
|
||||
this.fetchData();
|
||||
}
|
||||
}
|
||||
$onChanges(changes) {
|
||||
if (this.data) {
|
||||
this.copyData();
|
||||
}
|
||||
}
|
||||
$onDestroy() {
|
||||
this.deregisterCallback();
|
||||
}
|
||||
fetchData() {
|
||||
let id = this.data[this.idField];
|
||||
return new Promise((resolve, reject) => {
|
||||
this.$http.get(`${this.url}/${id}`).then(
|
||||
json => this.writeData(json, resolve),
|
||||
json => reject(json)
|
||||
);
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Submits the data and goes back in the history.
|
||||
*/
|
||||
submitBack() {
|
||||
this.submit().then(
|
||||
() => this.window.history.back()
|
||||
);
|
||||
}
|
||||
/**
|
||||
* Submits the data to the server.
|
||||
*
|
||||
* @return {Promise} The http request promise
|
||||
*/
|
||||
submit() {
|
||||
if (this.form) {
|
||||
this.form.$setSubmitted();
|
||||
|
||||
if (!this.form.$valid)
|
||||
return new Promise(
|
||||
(resolve, reject) => this.invalidForm(reject)
|
||||
);
|
||||
}
|
||||
if (!this.dataChanged()) {
|
||||
return new Promise(
|
||||
(resolve, reject) => this.noChanges(reject)
|
||||
);
|
||||
}
|
||||
let changedData = getModifiedData(this.data, this.orgData);
|
||||
|
||||
if (this.save) {
|
||||
this.save.model = changedData;
|
||||
return new Promise((resolve, reject) => {
|
||||
this.save.accept().then(
|
||||
json => this.writeData({data: json}, resolve),
|
||||
json => reject(json)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
// XXX: Alternative when mgCrud is not used
|
||||
|
||||
let id = this.orgData[this.idField];
|
||||
|
||||
if (id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.$http.put(`${this.url}/${id}`, changedData).then(
|
||||
json => this.writeData(json, resolve),
|
||||
json => reject(json)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
this.$http.post(this.url, this.data).then(
|
||||
json => this.writeData(json, resolve),
|
||||
json => reject(json)
|
||||
);
|
||||
});
|
||||
}
|
||||
writeData(json, resolve) {
|
||||
copyObject(json.data, this.data);
|
||||
this.copyData();
|
||||
resolve(json);
|
||||
}
|
||||
noChanges(resolve) {
|
||||
this.vnAppLogger.showMessage(
|
||||
this.$translate.instant('No changes to save')
|
||||
);
|
||||
resolve();
|
||||
}
|
||||
invalidForm(resolve) {
|
||||
this.vnAppLogger.showMessage(
|
||||
this.$translate.instant('Some fields are invalid')
|
||||
);
|
||||
resolve();
|
||||
}
|
||||
copyData() {
|
||||
this.orgData = copyObject(this.data);
|
||||
}
|
||||
callback(transition) {
|
||||
if (!this.state && this.dataChanged()) {
|
||||
this.state = transition.to().name;
|
||||
this.$scope.confirm.show();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
dataChanged() {
|
||||
return !isEqual(this.data, this.orgData);
|
||||
}
|
||||
onConfirmResponse(response) {
|
||||
if (response === 'ACCEPT') {
|
||||
copyObject(this.orgData, this.data);
|
||||
this.$state.go(this.state);
|
||||
} else {
|
||||
this.state = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
Watcher.$inject = ['$element', '$scope', '$state', '$transitions', '$http', 'vnAppLogger', '$translate'];
|
||||
|
||||
module.component('vnWatcher', {
|
||||
template: require('./index.html'),
|
||||
bindings: {
|
||||
url: '@?',
|
||||
idField: '@?',
|
||||
data: '<',
|
||||
form: '<',
|
||||
save: '<',
|
||||
get: '=?'
|
||||
},
|
||||
controller: Watcher
|
||||
});
|
|
@ -1 +1,2 @@
|
|||
node_modules
|
||||
node_modules
|
||||
config.json
|
Loading…
Reference in New Issue