Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix into 1466-print_refactor
gitea/salix/1466-print_refactor This commit looks good Details

This commit is contained in:
Joan Sanchez 2019-10-23 07:53:58 +02:00
commit b099fe206b
305 changed files with 3595 additions and 3367 deletions

View File

@ -9,25 +9,31 @@ module.exports = Self => {
{
arg: 'warehouseId',
type: 'Number',
description: 'The warehouse id'
description: 'The warehouse id',
required: true
}, {
arg: 'companyId',
type: 'Number',
description: 'The company id'
description: 'The company id',
required: true
}, {
arg: 'dmsTypeId',
type: 'Number',
description: 'The dms type id'
description: 'The dms type id',
required: true
}, {
arg: 'reference',
type: 'String'
type: 'String',
required: true
}, {
arg: 'description',
type: 'String'
type: 'String',
required: true
}, {
arg: 'hasFile',
type: 'Boolean',
description: 'True if has an attached file'
description: 'True if has an attached file',
required: true
}],
returns: {
type: 'Object',

View File

@ -52,6 +52,15 @@
},
"Postcode": {
"dataSource": "vn"
},
"UserPhoneType": {
"dataSource": "vn"
},
"UserPhone": {
"dataSource": "vn"
},
"UserLog": {
"dataSource": "vn"
}
}

View File

@ -0,0 +1,9 @@
let UserError = require('vn-loopback/util/user-error');
module.exports = Self => {
Self.rewriteDbError(function(err) {
if (err.code === 'ER_DUP_ENTRY')
return new UserError(`This phone already exists`);
return err;
});
};

View File

@ -2,7 +2,8 @@
"name": "UserPhone",
"base": "Loggable",
"log": {
"model":"UserLog"
"model":"UserLog",
"relation": "user"
},
"options": {
"mysql": {
@ -12,11 +13,15 @@
"properties": {
"id": {
"id": true,
"type": "String"
"type": "Number"
},
"phone": {
"type": "Number",
"required": true
},
"typeFk": {
"type": "String",
"required": true
}
},
"relations": {

View File

@ -1,6 +1,6 @@
CREATE TABLE `vn`.`userLog` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`originFk` int(11) NOT NULL,
`originFk` int(10) unsigned NOT NULL,
`userFk` int(10) unsigned DEFAULT NULL,
`action` set('insert','update','delete') COLLATE utf8_unicode_ci NOT NULL,
`creationDate` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
@ -13,6 +13,6 @@ CREATE TABLE `vn`.`userLog` (
PRIMARY KEY (`id`),
KEY `originFk` (`originFk`),
KEY `userFk` (`userFk`),
CONSTRAINT `userLog_ibfk_1` FOREIGN KEY (`originFk`) REFERENCES `client` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `userLog_ibfk_1` FOREIGN KEY (`originFk`) REFERENCES `account`.`user` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `userLog_ibfk_2` FOREIGN KEY (`userFk`) REFERENCES `account`.`user` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

View File

@ -2,7 +2,7 @@ CREATE TABLE `vn`.`userPhone` (
`id` INT NOT NULL AUTO_INCREMENT,
`userFk` INT(10) UNSIGNED NOT NULL,
`typeFk` VARCHAR(45) NOT NULL,
`phone` INT(15) NOT NULL,
`phone` VARCHAR(15) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE INDEX `UserFK_Phone` (`userFk` ASC, `phone` ASC));
@ -22,7 +22,7 @@ ADD CONSTRAINT `fgnUserFk`
ON UPDATE CASCADE;
insert into vn.userPhone(userFk,typeFk,phone)
select id,'PersonalPhone', phone
select id,'personalPhone', phone
from vn.client
where phone is not null;

View File

@ -351,16 +351,6 @@ INSERT INTO `vn`.`creditInsurance`(`id`, `creditClassification`, `credit`, `crea
(2, 2, 6000, DATE_ADD(CURDATE(), INTERVAL -2 MONTH), NULL),
(3, 3, 10000, DATE_ADD(CURDATE(), INTERVAL -3 MONTH), NULL);
INSERT INTO `vn`.`route`(`id`, `time`, `workerFk`, `created`, `vehicleFk`, `agencyModeFk`, `description`, `m3`, `cost`, `started`, `finished`)
VALUES
(1, '1899-12-30 12:15:00', 56, CURDATE(), 1, 7, 'first route', 2.7, 10, CURDATE(), CURDATE()),
(2, '1899-12-30 13:20:00', 56, CURDATE(), 1, 7, 'second route', 0.9, 20, CURDATE(), CURDATE()),
(3, '1899-12-30 14:30:00', 56, CURDATE(), 2, 7, 'third route', 1.1, 30, CURDATE(), CURDATE()),
(4, '1899-12-30 15:45:00', 56, CURDATE(), 3, 7, 'fourth route', 0.1, 40, CURDATE(), CURDATE()),
(5, '1899-12-30 16:00:00', 56, CURDATE(), 4, 8, 'fifth route', NULL, 50, CURDATE(), CURDATE()),
(6, NULL, 57, CURDATE(), 5, 8, 'sixth route', NULL, 60, CURDATE(), CURDATE()),
(7, NULL, 57, CURDATE(), 6, NULL, 'seventh route', NULL, 70, CURDATE(), CURDATE());
INSERT INTO `vn2008`.`empresa_grupo`(`empresa_grupo_id`, `grupo`)
VALUES
(1, 'Wayne Industries');
@ -456,32 +446,42 @@ INSERT INTO `vn`.`zone` (`id`, `name`, `hour`, `warehouseFk`, `agencyModeFk`, `t
(12, 'Zone entanglement', CONCAT(CURRENT_DATE(), ' ', TIME('22:00')), 4, 4, 0, 0, 0),
(13, 'Zone quantum break', CONCAT(CURRENT_DATE(), ' ', TIME('22:00')), 5, 5, 0, 0, 0);
INSERT INTO `vn`.`route`(`id`, `time`, `workerFk`, `created`, `vehicleFk`, `agencyModeFk`, `description`, `m3`, `cost`, `started`, `finished`, `zoneFk`)
VALUES
(1, '1899-12-30 12:15:00', 56, CURDATE(), 1, 1, 'first route', 1.8, 10, CURDATE(), CURDATE(), 1),
(2, '1899-12-30 13:20:00', 56, CURDATE(), 1, 2, 'second route', 0.2, 20, CURDATE(), CURDATE(), 9),
(3, '1899-12-30 14:30:00', 56, CURDATE(), 2, 3, 'third route', 0.5, 30, CURDATE(), CURDATE(), 10),
(4, '1899-12-30 15:45:00', 56, CURDATE(), 3, 4, 'fourth route', 0, 40, CURDATE(), CURDATE(), 12),
(5, '1899-12-30 16:00:00', 56, CURDATE(), 4, 5, 'fifth route', 0.1, 50, CURDATE(), CURDATE(), 13),
(6, NULL, 57, CURDATE(), 5, 7, 'sixth route', 1.7, 60, CURDATE(), CURDATE(), 3),
(7, NULL, 57, CURDATE(), 6, 8, 'seventh route', 0, 70, CURDATE(), CURDATE(), 5);
INSERT INTO `vn`.`ticket`(`id`, `priority`, `agencyModeFk`,`warehouseFk`,`routeFk`, `shipped`, `landed`, `clientFk`,`nickname`, `addressFk`, `refFk`, `isDeleted`, `zoneFk`, `created`)
VALUES
(1 , 3, 1, 1, 1, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), DATE_ADD(DATE_ADD(CURDATE(),INTERVAL -1 MONTH), INTERVAL +1 DAY), 101, 'Bat cave', 121, 'T1111111', 0, 1, DATE_ADD(CURDATE(), INTERVAL -1 MONTH)),
(2 , 1, 1, 1, 1, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), DATE_ADD(DATE_ADD(CURDATE(),INTERVAL -1 MONTH), INTERVAL +1 DAY), 104, 'Stark tower', 124, 'T1111111', 0, 1, DATE_ADD(CURDATE(), INTERVAL -1 MONTH)),
(3 , 1, 7, 1, 1, DATE_ADD(CURDATE(), INTERVAL -2 MONTH), DATE_ADD(DATE_ADD(CURDATE(),INTERVAL -2 MONTH), INTERVAL +1 DAY), 104, 'Stark tower', 124, 'T2222222', 0, 3, DATE_ADD(CURDATE(), INTERVAL -2 MONTH)),
(4 , 3, 2, 1, 1, DATE_ADD(CURDATE(), INTERVAL -3 MONTH), DATE_ADD(DATE_ADD(CURDATE(),INTERVAL -3 MONTH), INTERVAL +1 DAY), 104, 'Stark tower', 124, 'T3333333', 0, 9, DATE_ADD(CURDATE(), INTERVAL -3 MONTH)),
(5 , 3, 3, 3, 1, DATE_ADD(CURDATE(), INTERVAL -4 MONTH), DATE_ADD(DATE_ADD(CURDATE(),INTERVAL -4 MONTH), INTERVAL +1 DAY), 104, 'Stark tower', 124, 'T4444444', 0, 10, DATE_ADD(CURDATE(), INTERVAL -4 MONTH)),
(6 , 1, 3, 3, 1, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), DATE_ADD(DATE_ADD(CURDATE(),INTERVAL -1 MONTH), INTERVAL +1 DAY), 101, 'Mountain Drive Gotham', 1, 'A1111111', 0, 10, DATE_ADD(CURDATE(), INTERVAL -1 MONTH)),
(7 , NULL, 7, 1, 2, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 101, 'Mountain Drive Gotham', 1, NULL, 0, 3, CURDATE()),
(8 , NULL, 7, 1, 2, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 101, 'Bat cave', 121, NULL, 0, 3, CURDATE()),
(9 , NULL, 7, 1, 2, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 104, 'Stark tower', 124, NULL, 0, 3, CURDATE()),
(10, 1, 1, 5, 3, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 102, 'Ingram Street', 2, NULL, 0, 11, CURDATE()),
(11, 1, 7, 1, 3, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 102, 'NY roofs', 122, NULL, 0, 3, CURDATE()),
(12, 1, 1, 1, 3, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 103, 'Phone Box', 123, NULL, 0, 1, CURDATE()),
(13, 1, 7, 1, 2, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 103, 'Phone Box', 123, NULL, 0, 1, CURDATE()),
(14, 1, 2, 1, 3, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 104, 'Malibu Point', 4, NULL, 0, 9, CURDATE()),
(15, 1, 7, 1, 3, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 105, 'Plastic Cell', 125, NULL, 0, 3, CURDATE()),
(16, 1, 7, 1, 3, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 106, 'Many Places', 126, NULL, 0, 3, CURDATE()),
(17, 1, 7, 2, 3, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 106, 'Many Places', 126, NULL, 0, 3, CURDATE()),
(18, 1, 4, 4, 3, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 108, 'Cerebro', 128, NULL, 0, 12, CURDATE()),
(19, 1, 5, 5, 3, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 109, 'Somewhere in Thailand', 129, NULL, 1, 13, CURDATE()),
(20, 1, 5, 5, 3, DATE_ADD(CURDATE(), INTERVAL +1 MONTH), DATE_ADD(DATE_ADD(CURDATE(),INTERVAL +1 MONTH), INTERVAL +1 DAY), 109, 'Somewhere in Thailand', 129, NULL, 0, 13, DATE_ADD(CURDATE(), INTERVAL +1 MONTH)),
(21, NULL, 5, 5, NULL, DATE_ADD(CURDATE(), INTERVAL +1 MONTH), DATE_ADD(DATE_ADD(CURDATE(),INTERVAL +1 MONTH), INTERVAL +1 DAY), 109, 'Somewhere in Holland', 102, NULL, 0, 13, DATE_ADD(CURDATE(), INTERVAL +1 MONTH)),
(22, NULL, 5, 5, NULL, DATE_ADD(CURDATE(), INTERVAL +1 MONTH), DATE_ADD(DATE_ADD(CURDATE(),INTERVAL +1 MONTH), INTERVAL +1 DAY), 109, 'Somewhere in Japan', 103, NULL, 0, 13, DATE_ADD(CURDATE(), INTERVAL +1 MONTH)),
(23, NULL, 10, 1, NULL, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 101, 'address 21', 121, NULL, 0, 8, CURDATE()),
(24 ,NULL, 10, 1, NULL, CURDATE(), CURDATE(), 101, 'Bruce Wayne', 1, NULL, 0, 8, CURDATE());
(1 , 3, 1, 1, 1, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), DATE_ADD(DATE_ADD(CURDATE(),INTERVAL -1 MONTH), INTERVAL +1 DAY), 101, 'Bat cave', 121, 'T1111111', 0, 1, DATE_ADD(CURDATE(), INTERVAL -1 MONTH)),
(2 , 1, 1, 1, 1, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), DATE_ADD(DATE_ADD(CURDATE(),INTERVAL -1 MONTH), INTERVAL +1 DAY), 104, 'Stark tower', 124, 'T1111111', 0, 1, DATE_ADD(CURDATE(), INTERVAL -1 MONTH)),
(3 , 1, 7, 1, 6, DATE_ADD(CURDATE(), INTERVAL -2 MONTH), DATE_ADD(DATE_ADD(CURDATE(),INTERVAL -2 MONTH), INTERVAL +1 DAY), 104, 'Stark tower', 124, 'T2222222', 0, 3, DATE_ADD(CURDATE(), INTERVAL -2 MONTH)),
(4 , 3, 2, 1, 2, DATE_ADD(CURDATE(), INTERVAL -3 MONTH), DATE_ADD(DATE_ADD(CURDATE(),INTERVAL -3 MONTH), INTERVAL +1 DAY), 104, 'Stark tower', 124, 'T3333333', 0, 9, DATE_ADD(CURDATE(), INTERVAL -3 MONTH)),
(5 , 3, 3, 3, 3, DATE_ADD(CURDATE(), INTERVAL -4 MONTH), DATE_ADD(DATE_ADD(CURDATE(),INTERVAL -4 MONTH), INTERVAL +1 DAY), 104, 'Stark tower', 124, 'T4444444', 0, 10, DATE_ADD(CURDATE(), INTERVAL -4 MONTH)),
(6 , 1, 3, 3, 3, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), DATE_ADD(DATE_ADD(CURDATE(),INTERVAL -1 MONTH), INTERVAL +1 DAY), 101, 'Mountain Drive Gotham', 1, 'A1111111', 0, 10, DATE_ADD(CURDATE(), INTERVAL -1 MONTH)),
(7 , NULL, 7, 1, 6, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 101, 'Mountain Drive Gotham', 1, NULL, 0, 3, CURDATE()),
(8 , NULL, 7, 1, 6, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 101, 'Bat cave', 121, NULL, 0, 3, CURDATE()),
(9 , NULL, 7, 1, 6, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 104, 'Stark tower', 124, NULL, 0, 3, CURDATE()),
(10, 1, 1, 5, 1, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 102, 'Ingram Street', 2, NULL, 0, 1, CURDATE()),
(11, 1, 7, 1, 6, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 102, 'NY roofs', 122, NULL, 0, 3, CURDATE()),
(12, 1, 1, 1, 1, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 103, 'Phone Box', 123, NULL, 0, 1, CURDATE()),
(13, 1, 7, 1, 6, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 103, 'Phone Box', 123, NULL, 0, 3, CURDATE()),
(14, 1, 2, 1, NULL, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 104, 'Malibu Point', 4, NULL, 0, 9, CURDATE()),
(15, 1, 7, 1, 6, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 105, 'Plastic Cell', 125, NULL, 0, 3, CURDATE()),
(16, 1, 7, 1, 6, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 106, 'Many Places', 126, NULL, 0, 3, CURDATE()),
(17, 1, 7, 2, 6, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 106, 'Many Places', 126, NULL, 0, 3, CURDATE()),
(18, 1, 4, 4, 4, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 108, 'Cerebro', 128, NULL, 0, 12, CURDATE()),
(19, 1, 5, 5, 3, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 109, 'Somewhere in Thailand', 129, NULL, 1, 13, CURDATE()),
(20, 1, 5, 5, 3, DATE_ADD(CURDATE(), INTERVAL +1 MONTH), DATE_ADD(DATE_ADD(CURDATE(),INTERVAL +1 MONTH), INTERVAL +1 DAY), 109, 'Somewhere in Thailand', 129, NULL, 0, 13, DATE_ADD(CURDATE(), INTERVAL +1 MONTH)),
(21, NULL, 5, 5, 5, DATE_ADD(CURDATE(), INTERVAL +1 MONTH), DATE_ADD(DATE_ADD(CURDATE(),INTERVAL +1 MONTH), INTERVAL +1 DAY), 109, 'Somewhere in Holland', 102, NULL, 0, 13, DATE_ADD(CURDATE(), INTERVAL +1 MONTH)),
(22, NULL, 5, 5, 5, DATE_ADD(CURDATE(), INTERVAL +1 MONTH), DATE_ADD(DATE_ADD(CURDATE(),INTERVAL +1 MONTH), INTERVAL +1 DAY), 109, 'Somewhere in Japan', 103, NULL, 0, 13, DATE_ADD(CURDATE(), INTERVAL +1 MONTH)),
(23, NULL, 8, 1, 7, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 101, 'address 21', 121, NULL, 0, 5, CURDATE()),
(24 ,NULL, 8, 1, 7, CURDATE(), CURDATE(), 101, 'Bruce Wayne', 1, NULL, 0, 5, CURDATE());
INSERT INTO `vn`.`ticketObservation`(`id`, `ticketFk`, `observationTypeFk`, `description`)
VALUES
@ -1862,4 +1862,67 @@ INSERT INTO `vn`.`queuePriority`(`id`, `priority`)
VALUES
(1, 'Alta'),
(2, 'Normal'),
(3, 'Baja');
(3, 'Baja');
INSERT INTO `vn`.`userPhone`(`id`, `userFk`, `typeFk`, `phone`)
VALUES
(1, 101, 'personalPhone', 1111111111),
(2, 102, 'personalPhone', 1111111111),
(3, 103, 'personalPhone', 1111111111),
(4, 104, 'personalPhone', 1111111111),
(5, 105, 'personalPhone', 1111111111),
(6, 106, 'personalPhone', 1111111111),
(7, 107, 'personalPhone', 1111111111),
(8, 108, 'personalPhone', 1111111111),
(9, 109, 'personalPhone', 1111111111),
(10, 110, 'personalPhone', 1111111111),
(11, 111, 'personalPhone', 1111111111),
(12, 112, 'personalPhone', 1111111111),
(13, 1, 'personalPhone', 623111111),
(14, 2, 'personalPhone', 623111111),
(15, 3, 'personalPhone', 623111111),
(16, 5, 'personalPhone', 623111111),
(17, 6, 'personalPhone', 623111111),
(18, 9, 'personalPhone', 623111111),
(19, 13, 'personalPhone', 623111111),
(20, 15, 'personalPhone', 623111111),
(21, 16, 'personalPhone', 623111111),
(22, 17, 'personalPhone', 623111111),
(23, 18, 'personalPhone', 623111111),
(24, 19, 'personalPhone', 623111111),
(25, 20, 'personalPhone', 623111111),
(26, 21, 'personalPhone', 623111111),
(27, 22, 'personalPhone', 623111111),
(28, 30, 'personalPhone', 623111111),
(29, 31, 'personalPhone', 623111111),
(30, 32, 'personalPhone', 623111111),
(31, 34, 'personalPhone', 623111111),
(32, 35, 'personalPhone', 623111111),
(33, 36, 'personalPhone', 623111111),
(34, 37, 'personalPhone', 623111111),
(35, 38, 'personalPhone', 623111111),
(36, 39, 'personalPhone', 623111111),
(37, 40, 'personalPhone', 623111111),
(38, 41, 'personalPhone', 623111111),
(39, 42, 'personalPhone', 623111111),
(40, 43, 'personalPhone', 623111111),
(41, 44, 'personalPhone', 623111111),
(42, 45, 'personalPhone', 623111111),
(43, 47, 'personalPhone', 623111111),
(44, 48, 'personalPhone', 623111111),
(45, 50, 'personalPhone', 623111111),
(46, 51, 'personalPhone', 623111111),
(47, 52, 'personalPhone', 623111111),
(48, 54, 'personalPhone', 623111111),
(49, 55, 'personalPhone', 623111111),
(50, 56, 'personalPhone', 623111111),
(51, 57, 'personalPhone', 623111111),
(52, 58, 'personalPhone', 623111111),
(53, 59, 'personalPhone', 623111111),
(54, 60, 'personalPhone', 623111111),
(55, 61, 'personalPhone', 623111111),
(56, 65, 'personalPhone', 623111111),
(57, 66, 'personalPhone', 623111111),
(65, 107, 'businessPhone', 700987987),
(67, 106, 'businessPhone', 1111111112),
(68, 106, 'personalPhone', 1111111113);

View File

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

View File

@ -6,6 +6,121 @@ import config from './config.js';
let currentUser;
let asyncActions = {
// Generic extensions
clickIfExists: async function(selector) {
let exists = await this.exists(selector);
if (exists) await this.click(selector);
return exists;
},
hasClass: async function(selector, className) {
return await this.evaluate((selector, className) => {
document.querySelector(selector).classList.contains(className);
}, selector, className);
},
parsedUrl: async function() {
return new URL(await this.url());
},
// Salix specific extensions
changeLanguageToEnglish: async function() {
let langSelector = '.user-popover vn-autocomplete[ng-model="$ctrl.lang"]';
let lang = await this.waitToClick('#user')
.wait(langSelector)
.waitToGetProperty(`${langSelector} input`, 'value');
if (lang !== 'English')
await this.autocompleteSearch(langSelector, 'English');
},
doLogin: async function(userName, password) {
if (password == null) password = 'nightmare';
await this.wait(`vn-login [name=user]`)
.clearInput(`vn-login [name=user]`)
.write(`vn-login [name=user]`, userName)
.write(`vn-login [name=password]`, password)
.click(`vn-login button[type=submit]`);
},
login: async function(userName) {
if (currentUser !== userName) {
let logoutClicked = await this.clickIfExists('#logout');
if (logoutClicked) {
let buttonSelector = '.vn-dialog.shown button[response=ACCEPT]';
this.wait(buttonSelector => {
return document.querySelector(buttonSelector) != null
|| location.hash == '#!/login';
}, buttonSelector);
await this.clickIfExists(buttonSelector);
}
try {
await this.waitForURL('#!/login');
} catch (e) {
this.goto(`${config.url}/#!/login`);
}
await this.doLogin(userName, null)
.waitForURL('#!/')
.changeLanguageToEnglish();
currentUser = userName;
} else
await this.waitToClick('vn-topbar a[ui-sref="home"]');
},
waitForLogin: async function(userName) {
await this.login(userName);
},
selectModule: async function(moduleName) {
let snakeName = moduleName.replace(/[\w]([A-Z])/g, m => {
return m[0] + '-' + m[1];
}).toLowerCase();
await this.waitToClick(`vn-home a[ui-sref="${moduleName}.index"]`)
.waitForURL(snakeName);
},
loginAndModule: async function(userName, moduleName) {
await this.login(userName)
.selectModule(moduleName);
},
datePicker: async function(selector, changeMonth, day) {
let date = new Date();
if (changeMonth) date.setMonth(date.getMonth() + changeMonth);
date.setDate(day ? day : 16);
date = date.toISOString().substr(0, 10);
await this.wait(selector)
.evaluate((selector, date) => {
let input = document.querySelector(selector).$ctrl.input;
input.value = date;
input.dispatchEvent(new Event('change'));
}, selector, date);
},
pickTime: async function(selector, time) {
await this.wait(selector)
.evaluate((selector, time) => {
let input = document.querySelector(selector).$ctrl.input;
input.value = time;
input.dispatchEvent(new Event('change'));
}, selector, time);
},
isDisabled: async function(selector) {
return await this.hasClass(selector, 'disabled');
}
};
let actions = {
clearTextarea: function(selector, done) {
this.wait(selector)
@ -28,98 +143,6 @@ let actions = {
.catch(done);
},
login: function(userName, done) {
if (currentUser)
this.waitToClick('#logout');
let doLogin = () => {
this.wait(`vn-login input[name=user]`)
.clearInput(`vn-login input[name=user]`)
.write(`vn-login input[name=user]`, userName)
.write(`vn-login input[name=password]`, 'nightmare')
.click(`vn-login input[type=submit]`)
.then(() => {
currentUser = userName;
done();
})
.catch(done);
};
this.waitForURL('#!/login')
.then(doLogin)
.catch(() => {
this.goto(`${config.url}/#!/login`)
.then(doLogin)
.catch(done);
});
},
waitForLogin: function(userName, done) {
if (currentUser === userName) {
return this.waitToClick('vn-topbar a[ui-sref="home"]')
.waitForURL('#!/')
.changeLanguageToEnglish()
.then(done)
.catch(done);
}
return this.login(userName)
.waitForURL('#!/')
.url()
.changeLanguageToEnglish()
.then(done)
.catch(done);
},
resetLogin: function(done) {
this.then(() => {
currentUser = undefined;
done();
})
.catch(done);
},
changeLanguageToEnglish: function(done) {
let langSelector = '.user-popover vn-autocomplete[ng-model="$ctrl.lang"]';
this.waitToClick('#user')
.wait(langSelector)
.waitToGetProperty(`${langSelector} input`, 'value')
.then(lang => {
if (lang === 'English') {
this.then(done)
.catch(done);
} else {
this.autocompleteSearch(langSelector, 'English')
.then(done)
.catch(done);
}
});
},
selectModule: function(moduleName, done) {
let snakeName = moduleName.replace(/[\w]([A-Z])/g, m => {
return m[0] + '-' + m[1];
}).toLowerCase();
this.waitToClick(`vn-home a[ui-sref="${moduleName}.index"]`)
.waitForURL(snakeName)
.then(done)
.catch(done);
},
loginAndModule: function(userName, moduleName, done) {
this.waitForLogin(userName)
.selectModule(moduleName)
.then(done)
.catch(done);
},
parsedUrl: function(done) {
this.url()
.then(url => {
done(null, new URL(url));
}).catch(done);
},
getProperty: function(selector, property, done) {
this.evaluate_now((selector, property) => {
return document.querySelector(selector)[property].replace(/\s+/g, ' ').trim();
@ -419,51 +442,6 @@ let actions = {
});
},
pickTime: function(selector, time, done) {
this.wait(selector)
.evaluate((selector, time) => {
let input = document.querySelector(selector);
input.value = time;
input.dispatchEvent(new Event('change'));
}, selector, time)
.then(done)
.catch(done);
},
datePicker: function(selector, changeMonth, day, done) {
this.wait(selector)
.mousedown(`${selector} input`)
.wait('.flatpickr-calendar.open');
if (changeMonth > 0)
this.mousedown(`.flatpickr-calendar.open .flatpickr-next-month`);
if (changeMonth < 0)
this.mousedown(`.flatpickr-calendar.open .flatpickr-prev-month`);
let daySelector;
if (!day)
daySelector = `.flatpickr-calendar.open .flatpickr-day:nth-child(16)`;
if (day)
daySelector = `.flatpickr-calendar.open .flatpickr-day[aria-label~="${day},"]:not(.prevMonthDay):not(.nextMonthDay)`;
this.wait(selector => {
return document.querySelector(selector);
}, daySelector)
.evaluate(selector => {
let event = new MouseEvent('mousedown', {
bubbles: true,
cancelable: true,
view: window
});
document.querySelector(selector).dispatchEvent(event);
}, daySelector)
.then(done)
.catch(() => {
done(new Error(`.datePicker(), for ${daySelector} timed out`));
});
},
reloadSection: function(sectionRoute, done) {
this.waitToClick('vn-icon[icon="desktop_windows"]')
.wait('vn-card.summary')
@ -516,6 +494,16 @@ let actions = {
},
};
for (let name in asyncActions) {
let fn = asyncActions[name];
Nightmare.action(name, function(...args) {
let done = args[args.length - 1];
fn.apply(this, args)
.then(res => done(null, res), done);
});
}
Object.keys(actions).forEach(function(name) {
let fn = actions[name];
Nightmare.action(name, fn);

View File

@ -1,4 +1,6 @@
const Nightmare = require('nightmare');
const config = require('./config.js');
let nightmare;
module.exports = function createNightmare(width = 1280, height = 720) {
@ -25,5 +27,5 @@ module.exports = function createNightmare(width = 1280, height = 720) {
});
nightmare.header('Accept-Language', 'en');
return nightmare;
return nightmare.goto(config.url);
};

View File

@ -1,4 +1,3 @@
import components from './components_selectors.js';
export default {
globalItems: {
@ -22,29 +21,29 @@ export default {
acceptButton: 'vn-confirm button[response=ACCEPT]'
},
clientsIndex: {
searchClientInput: `${components.vnTextfield}`,
searchClientInput: `vn-textfield input`,
searchButton: 'vn-searchbar vn-icon[icon="search"]',
searchResult: 'vn-client-index .vn-list-item',
createClientButton: `${components.vnFloatButton}`,
createClientButton: `vn-float-button`,
othersButton: 'vn-left-menu li[name="Others"] > a'
},
createClientView: {
name: `${components.vnTextfield}[name="name"]`,
taxNumber: `${components.vnTextfield}[name="fi"]`,
socialName: `${components.vnTextfield}[name="socialName"]`,
street: `${components.vnTextfield}[name="street"]`,
postcode: `${components.vnTextfield}[name="postcode"]`,
city: `${components.vnTextfield}[name="city"]`,
name: `vn-textfield input[name="name"]`,
taxNumber: `vn-textfield input[name="fi"]`,
socialName: `vn-textfield input[name="socialName"]`,
street: `vn-textfield input[name="street"]`,
postcode: `vn-textfield input[name="postcode"]`,
city: `vn-textfield input[name="city"]`,
province: `vn-autocomplete[ng-model="$ctrl.client.provinceFk"]`,
country: `vn-autocomplete[ng-model="$ctrl.client.countryFk"]`,
userName: `${components.vnTextfield}[name="userName"]`,
email: `${components.vnTextfield}[name="email"]`,
userName: `vn-textfield input[name="userName"]`,
email: `vn-textfield input[name="email"]`,
salesPersonAutocomplete: `vn-autocomplete[ng-model="$ctrl.client.salesPersonFk"]`,
createButton: `${components.vnSubmit}`,
createButton: `button[type=submit]`,
cancelButton: 'vn-button[href="#!/client/index"]'
},
clientDescriptor: {
moreMenu: 'vn-client-descriptor vn-icon-menu > div > vn-icon',
moreMenu: 'vn-client-descriptor vn-icon-menu[icon=more_vert]',
simpleTicketButton: '.vn-popover.shown .vn-drop-down li'
},
clientBasicData: {
@ -56,17 +55,17 @@ export default {
emailInput: 'vn-textfield[ng-model="$ctrl.client.email"] input',
salesPersonAutocomplete: 'vn-autocomplete[ng-model="$ctrl.client.salesPersonFk"]',
channelAutocomplete: 'vn-autocomplete[ng-model="$ctrl.client.contactChannelFk"]',
saveButton: `${components.vnSubmit}`
saveButton: `button[type=submit]`
},
clientFiscalData: {
fiscalDataButton: 'vn-left-menu a[ui-sref="client.card.fiscalData"]',
socialNameInput: `${components.vnTextfield}[name="socialName"]`,
fiscalIdInput: `${components.vnTextfield}[name="fi"]`,
equalizationTaxCheckbox: 'vn-check[label="Is equalizated"]',
socialNameInput: `vn-textfield input[name="socialName"]`,
fiscalIdInput: `vn-textfield input[name="fi"]`,
equalizationTaxCheckbox: 'vn-check[ng-model="$ctrl.client.isEqualizated"]',
acceptPropagationButton: 'vn-client-fiscal-data > vn-confirm button[response=ACCEPT]',
addressInput: `${components.vnTextfield}[name="street"]`,
postcodeInput: `${components.vnTextfield}[name="postcode"]`,
cityInput: `${components.vnTextfield}[name="city"]`,
addressInput: `vn-textfield input[name="street"]`,
postcodeInput: `vn-textfield input[name="postcode"]`,
cityInput: `vn-textfield input[name="city"]`,
provinceAutocomplete: 'vn-autocomplete[ng-model="$ctrl.client.provinceFk"]',
countryAutocomplete: 'vn-autocomplete[ng-model="$ctrl.client.countryFk"]',
activeCheckbox: 'vn-check[label="Active"]',
@ -76,12 +75,12 @@ export default {
hasToInvoiceCheckbox: 'vn-check[label="Has to invoice"]',
invoiceByMailCheckbox: 'vn-check[label="Invoice by mail"]',
viesCheckbox: 'vn-check[label="Vies"]',
saveButton: `${components.vnSubmit}`
saveButton: `button[type=submit]`
},
clientBillingData: {
payMethodAutocomplete: 'vn-client-billing-data vn-autocomplete[ng-model="$ctrl.client.payMethodFk"]',
IBANInput: `vn-client-billing-data ${components.vnTextfield}[name="iban"]`,
dueDayInput: `vn-client-billing-data ${components.vnInputNumber}[name="dueDay"]`,
IBANInput: `vn-client-billing-data vn-textfield input[name="iban"]`,
dueDayInput: `vn-client-billing-data vn-input-number input[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"]',
@ -92,20 +91,20 @@ export default {
newBankEntityBIC: 'vn-client-billing-data > vn-dialog vn-textfield[label="Swift / BIC"] input',
newBankEntityCode: 'vn-client-billing-data > vn-dialog vn-textfield[label="Entity Code"] input',
acceptBankEntityButton: 'vn-client-billing-data > vn-dialog button[response="ACCEPT"]',
saveButton: `${components.vnSubmit}`
saveButton: `button[type=submit]`
},
clientAddresses: {
addressesButton: 'vn-left-menu a[ui-sref="client.card.address.index"]',
createAddress: `vn-client-address-index ${components.vnFloatButton}`,
createAddress: `vn-client-address-index vn-float-button`,
defaultCheckboxInput: 'vn-check[label="Default"]',
consigneeInput: `${components.vnTextfield}[name="nickname"]`,
streetAddressInput: `${components.vnTextfield}[name="street"]`,
postcodeInput: `${components.vnTextfield}[name="postalCode"]`,
cityInput: `${components.vnTextfield}[name="city"]`,
consigneeInput: `vn-textfield input[name="nickname"]`,
streetAddressInput: `vn-textfield input[name="street"]`,
postcodeInput: `vn-textfield input[name="postalCode"]`,
cityInput: `vn-textfield input[name="city"]`,
provinceAutocomplete: 'vn-autocomplete[ng-model="$ctrl.address.provinceFk"]',
agencyAutocomplete: 'vn-autocomplete[ng-model="$ctrl.address.agencyModeFk"]',
phoneInput: `${components.vnTextfield}[name="phone"]`,
mobileInput: `${components.vnTextfield}[name="mobile"]`,
phoneInput: `vn-textfield input[name="phone"]`,
mobileInput: `vn-textfield input[name="mobile"]`,
defaultAddress: 'vn-client-address-index div:nth-child(1) div[name="street"]',
secondMakeDefaultStar: 'vn-client-address-index vn-card div:nth-child(2) vn-icon-button[icon="star_border"]',
firstEditAddress: 'vn-client-address-index div:nth-child(1) > a',
@ -117,34 +116,34 @@ export default {
secondObservationTypeAutocomplete: 'vn-client-address-edit [name=observations] :nth-child(2) [ng-model="observation.observationTypeFk"]',
secondObservationDescriptionInput: 'vn-client-address-edit [name=observations] :nth-child(2) [ng-model="observation.description"] input',
addObservationButton: 'vn-client-address-edit div[name="observations"] vn-icon-button[icon="add_circle"]',
saveButton: `${components.vnSubmit}`,
saveButton: `button[type=submit]`,
cancelCreateAddressButton: 'button[ui-sref="client.card.address.index"]',
cancelEditAddressButton: 'vn-client-address-edit > form > vn-button-bar > vn-button > button'
},
clientWebAccess: {
webAccessButton: 'vn-left-menu a[ui-sref="client.card.webAccess"]',
enableWebAccessCheckbox: 'vn-check[label="Enable web access"]',
userNameInput: `${components.vnTextfield}[name="name"]`,
saveButton: `${components.vnSubmit}`
userNameInput: `vn-textfield input[name="name"]`,
saveButton: `button[type=submit]`
},
clientNotes: {
addNoteFloatButton: `${components.vnFloatButton}`,
addNoteFloatButton: `vn-float-button`,
noteInput: 'vn-textarea[label="Note"]',
saveButton: `${components.vnSubmit}`,
saveButton: `button[type=submit]`,
firstNoteText: 'vn-client-note .text'
},
clientCredit: {
addCreditFloatButton: `${components.vnFloatButton}`,
creditInput: `${components.vnInputNumber}[name="credit"]`,
saveButton: `${components.vnSubmit}`,
addCreditFloatButton: `vn-float-button`,
creditInput: `vn-input-number input[name="credit"]`,
saveButton: `button[type=submit]`,
firstCreditText: 'vn-client-credit-index vn-card > div vn-table vn-tbody > vn-tr'
},
clientGreuge: {
addGreugeFloatButton: `${components.vnFloatButton}`,
amountInput: `${components.vnInputNumber}[name="amount"]`,
descriptionInput: `${components.vnTextfield}[name="description"]`,
addGreugeFloatButton: `vn-float-button`,
amountInput: `vn-input-number input[name="amount"]`,
descriptionInput: `vn-textfield input[name="description"]`,
typeAutocomplete: 'vn-autocomplete[ng-model="$ctrl.greuge.greugeTypeFk"]',
saveButton: `${components.vnSubmit}`,
saveButton: `button[type=submit]`,
firstGreugeText: 'vn-client-greuge-index vn-card > div vn-table vn-tbody > vn-tr'
},
clientMandate: {
@ -163,7 +162,7 @@ export default {
clientBalance: {
balanceButton: 'vn-left-menu a[ui-sref="client.card.balance.index"]',
companyAutocomplete: 'vn-client-balance-index vn-autocomplete[ng-model="$ctrl.companyFk"]',
newPaymentButton: `${components.vnFloatButton}`,
newPaymentButton: `vn-float-button`,
newPaymentBank: 'vn-client-balance-create vn-autocomplete[ng-model="$ctrl.receipt.bankFk"]',
newPaymentAmountInput: 'vn-client-balance-create vn-input-number[ng-model="$ctrl.receipt.amountPaid"] input',
saveButton: 'vn-client-balance-create vn-button[label="Save"]',
@ -182,7 +181,7 @@ export default {
},
itemsIndex: {
searchIcon: 'vn-item-index vn-searchbar vn-icon[icon="search"]',
createItemButton: `${components.vnFloatButton}`,
createItemButton: `vn-float-button`,
searchResult: 'vn-item-index a.vn-tr',
searchResultPreviewButton: 'vn-item-index .buttons > [icon="desktop_windows"]',
searchResultCloneButton: 'vn-item-index .buttons > [icon="icon-clone"]',
@ -208,16 +207,16 @@ export default {
saveFieldsButton: 'vn-item-index vn-dialog vn-horizontal:nth-child(16) > vn-button > button'
},
itemCreateView: {
temporalName: `${components.vnTextfield}[name="provisionalName"]`,
temporalName: `vn-textfield input[name="provisionalName"]`,
typeAutocomplete: 'vn-autocomplete[ng-model="$ctrl.item.typeFk"]',
intrastatAutocomplete: 'vn-autocomplete[ng-model="$ctrl.item.intrastatFk"]',
originAutocomplete: 'vn-autocomplete[ng-model="$ctrl.item.originFk"]',
createButton: `${components.vnSubmit}`,
cancelButton: 'button[ui-sref="item.index"]'
createButton: `button[type=submit]`,
cancelButton: 'vn-button[ui-sref="item.index"]'
},
itemDescriptor: {
goBackToModuleIndexButton: 'vn-item-descriptor a[href="#!/item/index"]',
moreMenu: 'vn-item-descriptor vn-icon-menu > div > vn-icon',
moreMenu: 'vn-item-descriptor vn-icon-menu[icon=more_vert]',
moreMenuRegularizeButton: '.vn-popover.shown .vn-drop-down li[name="Regularize stock"]',
regularizeQuantityInput: 'vn-item-descriptor vn-dialog tpl-body > div > vn-textfield input',
regularizeWarehouseAutocomplete: 'vn-item-descriptor vn-dialog vn-autocomplete[ng-model="$ctrl.warehouseFk"]',
@ -238,7 +237,7 @@ export default {
longNameInput: 'vn-textfield[ng-model="$ctrl.item.longName"] input',
isActiveCheckbox: 'vn-check[label="Active"]',
priceInKgCheckbox: 'vn-check[label="Price in kg"]',
submitBasicDataButton: `${components.vnSubmit}`
submitBasicDataButton: `button[type=submit]`
},
itemTags: {
goToItemIndexButton: 'vn-item-descriptor [ui-sref="item.index"]',
@ -257,19 +256,19 @@ export default {
seventhValueInput: 'vn-item-tags vn-horizontal:nth-child(7) > vn-textfield[label="Value"] input',
seventhRelevancyInput: 'vn-item-tags vn-horizontal:nth-child(7) > vn-textfield[label="Relevancy"] input',
addItemTagButton: 'vn-item-tags vn-icon-button[icon="add_circle"]',
submitItemTagsButton: `vn-item-tags ${components.vnSubmit}`
submitItemTagsButton: `vn-item-tags button[type=submit]`
},
itemTax: {
undoChangesButton: 'vn-item-tax vn-button-bar > vn-button[label="Undo changes"]',
firstClassAutocomplete: 'vn-item-tax vn-horizontal:nth-child(1) > vn-autocomplete[ng-model="tax.taxClassFk"]',
secondClassAutocomplete: 'vn-item-tax vn-horizontal:nth-child(2) > vn-autocomplete[ng-model="tax.taxClassFk"]',
thirdClassAutocomplete: 'vn-item-tax vn-horizontal:nth-child(3) > vn-autocomplete[ng-model="tax.taxClassFk"]',
submitTaxButton: `vn-item-tax ${components.vnSubmit}`
submitTaxButton: `vn-item-tax button[type=submit]`
},
itemBarcodes: {
addBarcodeButton: 'vn-item-barcode vn-icon[icon="add_circle"]',
thirdCodeInput: `vn-item-barcode vn-horizontal:nth-child(3) > ${components.vnTextfield}`,
submitBarcodesButton: `vn-item-barcode ${components.vnSubmit}`,
thirdCodeInput: `vn-item-barcode vn-horizontal:nth-child(3) > vn-textfield input`,
submitBarcodesButton: `vn-item-barcode button[type=submit]`,
firstCodeRemoveButton: 'vn-item-barcode vn-horizontal vn-none vn-icon[icon="delete"]'
},
itemNiches: {
@ -281,13 +280,13 @@ export default {
secondNicheRemoveButton: 'vn-item-niche vn-horizontal:nth-child(2) > vn-none > vn-icon-button[icon="delete"]',
thirdWarehouseAutocomplete: 'vn-item-niche vn-horizontal:nth-child(3) > vn-autocomplete[ng-model="niche.warehouseFk"]',
thirdCodeInput: 'vn-item-niche vn-horizontal:nth-child(3) > vn-textfield[label="Code"] input',
submitNichesButton: `vn-item-niche ${components.vnSubmit}`
submitNichesButton: `vn-item-niche button[type=submit]`
},
itemBotanical: {
botanicalInput: `vn-item-botanical vn-horizontal:nth-child(1) > ${components.vnTextfield}`,
botanicalInput: `vn-item-botanical vn-horizontal:nth-child(1) > vn-textfield input`,
genusAutocomplete: 'vn-item-botanical vn-autocomplete[ng-model="$ctrl.botanical.genusFk"]',
speciesAutocomplete: 'vn-item-botanical vn-autocomplete[ng-model="$ctrl.botanical.specieFk"]',
submitBotanicalButton: `vn-item-botanical ${components.vnSubmit}`
submitBotanicalButton: `vn-item-botanical button[type=submit]`
},
itemSummary: {
basicData: 'vn-item-summary [name="basicData"]',
@ -330,13 +329,13 @@ export default {
searchResult: 'vn-ticket-index vn-card > div > vn-table > div > vn-tbody > a.vn-tr',
searchWeeklyResult: 'vn-ticket-weekly-index vn-table vn-tbody > vn-tr',
searchResultDate: 'vn-ticket-index vn-table vn-tbody > a:nth-child(1) > vn-td:nth-child(5)',
searchTicketInput: `vn-ticket-index ${components.vnTextfield}`,
searchWeeklyTicketInput: `vn-ticket-weekly-index ${components.vnTextfield}`,
searchTicketInput: `vn-ticket-index vn-textfield input`,
searchWeeklyTicketInput: `vn-ticket-weekly-index vn-textfield input`,
searchWeeklyClearInput: 'vn-ticket-weekly-index vn-searchbar vn-icon[icon=clear]',
advancedSearchButton: 'vn-ticket-search-panel vn-submit[label="Search"] input',
advancedSearchButton: 'vn-ticket-search-panel button[type=submit]',
searchButton: 'vn-ticket-index vn-searchbar vn-icon[icon="search"]',
searchWeeklyButton: 'vn-ticket-weekly-index vn-searchbar vn-icon[icon="search"]',
moreMenu: 'vn-ticket-index vn-icon-menu[vn-id="more-button"] > div > vn-icon',
moreMenu: 'vn-ticket-index vn-icon-menu[icon=more_vert]',
moreMenuWeeklyTickets: '.vn-popover.shown .vn-drop-down li:nth-child(2)',
sixthWeeklyTicket: 'vn-ticket-weekly-index vn-table vn-tr:nth-child(6) vn-autocomplete[ng-model="weekly.weekDay"] input',
weeklyTicket: 'vn-ticket-weekly-index vn-table > div > vn-tbody > vn-tr',
@ -349,13 +348,13 @@ export default {
deliveryDateInput: 'vn-ticket-create vn-date-picker[ng-model="$ctrl.landed"]',
warehouseAutocomplete: 'vn-ticket-create vn-autocomplete[ng-model="$ctrl.warehouseFk"]',
agencyAutocomplete: 'vn-ticket-create vn-autocomplete[ng-model="$ctrl.ticket.agencyModeFk"]',
createButton: `${components.vnSubmit}`
createButton: `button[type=submit]`
},
ticketDescriptor: {
idLabelValue: 'vn-ticket-descriptor vn-label-value[label="Id"]',
stateLabelValue: 'vn-ticket-descriptor vn-label-value[label="State"]',
goBackToModuleIndexButton: 'vn-ticket-descriptor a[ui-sref="ticket.index"]',
moreMenu: 'vn-ticket-descriptor vn-icon-menu > div > vn-icon',
moreMenu: 'vn-ticket-descriptor vn-icon-menu[icon=more_vert]',
moreMenuAddStowaway: '.vn-popover.shown .vn-drop-down li[name="Add stowaway"]',
moreMenuDeleteStowawayButton: '.vn-popover.shown .vn-drop-down li[name="Remove stowaway"]',
moreMenuAddToTurn: '.vn-popover.shown .vn-drop-down li[name="Add turn"]',
@ -363,9 +362,9 @@ export default {
moreMenuMakeInvoice: '.vn-popover.shown .vn-drop-down li[name="Make invoice"]',
moreMenuChangeShippedHour: '.vn-popover.shown .vn-drop-down li[name="Change shipped hour"]',
changeShippedHourDialog: 'vn-ticket-descriptor vn-dialog[vn-id="changeShippedDialog"]',
changeShippedHourInput: 'vn-ticket-descriptor vn-dialog[vn-id="changeShippedDialog"] vn-input-time[vn-id="newShipped"]',
changeShippedHourInput: 'vn-dialog[vn-id="changeShippedDialog"] [ng-model="$ctrl.newShipped"]',
addStowawayDialogFirstTicket: 'vn-ticket-descriptor > vn-add-stowaway > vn-dialog vn-table vn-tbody vn-tr',
shipButton: 'vn-ticket-descriptor > div > div.body > div.quicklinks vn-icon[icon="icon-stowaway"]',
shipButton: 'vn-ticket-descriptor vn-icon[icon="icon-stowaway"]',
thursdayButton: 'vn-ticket-descriptor > vn-dialog > div > form > div.body > tpl-body > div > vn-tool-bar > vn-button:nth-child(4)',
saturdayButton: 'vn-ticket-descriptor > vn-dialog > div > form > div.body > tpl-body > div > vn-tool-bar > vn-button:nth-child(6)',
closeStowawayDialog: 'vn-ticket-descriptor > vn-add-stowaway > vn-dialog > div > button[class="close"]',
@ -380,7 +379,7 @@ export default {
addNoteButton: 'vn-icon[icon="add_circle"]',
firstNoteTypeAutocomplete: 'vn-autocomplete[ng-model="observation.observationTypeFk"]',
firstDescriptionInput: 'vn-textfield[label="Description"] input',
submitNotesButton: `${components.vnSubmit}`
submitNotesButton: `button[type=submit]`
},
ticketExpedition: {
expeditionButton: 'vn-left-menu a[ui-sref="ticket.card.expedition"]',
@ -395,7 +394,7 @@ export default {
firstRemovePackageButton: 'vn-icon-button[vn-tooltip="Remove package"]',
addPackageButton: 'vn-icon-button[vn-tooltip="Add package"]',
clearPackageAutocompleteButton: 'vn-autocomplete[label="Package"] .icons > vn-icon[icon=clear]',
savePackagesButton: `${components.vnSubmit}`
savePackagesButton: `button[type=submit]`
},
ticketSales: {
saleButton: 'vn-left-menu a[ui-sref="ticket.card.sale"]',
@ -421,7 +420,6 @@ export default {
firstSaleQuantity: 'vn-input-number[ng-model="sale.quantity"]:nth-child(1) input',
firstSaleQuantityCell: 'vn-ticket-sale vn-tr:nth-child(1) > vn-td-editable:nth-child(5)',
firstSaleQuantityClearInput: 'vn-textfield[ng-model="sale.quantity"] div.suffix > i',
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',
@ -461,9 +459,9 @@ export default {
},
ticketTracking: {
trackingButton: 'vn-left-menu a[ui-sref="ticket.card.tracking.index"]',
createStateButton: `${components.vnFloatButton}`,
createStateButton: `vn-float-button`,
stateAutocomplete: 'vn-ticket-tracking-edit vn-autocomplete[ng-model="$ctrl.stateFk"]',
saveButton: `${components.vnSubmit}`,
saveButton: `button[type=submit]`,
cancelButton: 'vn-ticket-tracking-edit vn-button[ui-sref="ticket.card.tracking.index"]'
},
ticketBasicData: {
@ -472,8 +470,8 @@ export default {
addressAutocomplete: 'vn-autocomplete[ng-model="$ctrl.ticket.addressFk"]',
agencyAutocomplete: 'vn-autocomplete[ng-model="$ctrl.agencyModeId"]',
zoneAutocomplete: 'vn-autocomplete[ng-model="$ctrl.zoneId"]',
nextStepButton: 'vn-step-control > section > section.buttons > section:nth-child(2) > vn-button',
finalizeButton: 'vn-step-control > section > section.buttons > section:nth-child(2) > vn-submit',
nextStepButton: 'vn-step-control .buttons > section:last-child vn-button',
finalizeButton: 'vn-step-control .buttons > section:last-child button[type=submit]',
stepTwoTotalPriceDif: 'vn-ticket-basic-data-step-two > form > vn-card > div > vn-horizontal > table > tfoot > tr > td:nth-child(4)',
chargesReasonAutocomplete: 'vn-autocomplete[ng-model="$ctrl.ticket.option"]',
},
@ -484,11 +482,11 @@ export default {
addRequestButton: 'vn-ticket-request-index > a > vn-float-button > button',
request: 'vn-ticket-request-index vn-table vn-tr',
descriptionInput: 'vn-ticket-request-create > form > div > vn-card > div > vn-horizontal:nth-child(1) > vn-textfield input',
atenderAutocomplete: 'vn-ticket-request-create vn-autocomplete[ng-model="$ctrl.ticketRequest.atenderFk"]',
atenderAutocomplete: 'vn-ticket-request-create vn-autocomplete[ng-model="$ctrl.ticketRequest.attenderFk"]',
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',
saveButton: 'vn-ticket-request-create button[type=submit]',
firstDescription: 'vn-ticket-request-index vn-table vn-tr:nth-child(1) > vn-td:nth-child(2)',
},
@ -500,7 +498,7 @@ export default {
},
ticketService: {
addServiceButton: 'vn-ticket-service vn-icon-button[vn-tooltip="Add service"] > button',
firstAddDescriptionButton: 'vn-ticket-service vn-icon-button[vn-tooltip="New service type"] > button',
firstAddDescriptionButton: 'vn-ticket-service vn-icon-button[vn-tooltip="New service type"]',
firstDescriptionAutocomplete: 'vn-ticket-service vn-autocomplete[ng-model="service.description"]',
firstQuantityInput: 'vn-ticket-service vn-input-number[label="Quantity"] input',
firstPriceInput: 'vn-ticket-service vn-input-number[label="Price"] input',
@ -508,22 +506,22 @@ export default {
fistDeleteServiceButton: 'vn-ticket-service form vn-horizontal:nth-child(1) vn-icon-button[icon="delete"]',
newDescriptionInput: 'vn-ticket-service > vn-dialog vn-textfield[ng-model="$ctrl.newServiceType.name"] input',
serviceLine: 'vn-ticket-service > form > vn-card > div > vn-one:nth-child(2) > vn-horizontal',
saveServiceButton: `${components.vnSubmit}`,
saveServiceButton: `button[type=submit]`,
saveDescriptionButton: 'vn-ticket-service > vn-dialog[vn-id="createServiceTypeDialog"] > div > form > div.buttons > tpl-buttons > button'
},
createStateView: {
stateAutocomplete: 'vn-autocomplete[ng-model="$ctrl.stateFk"]',
workerAutocomplete: 'vn-autocomplete[ng-model="$ctrl.workerFk"]',
clearStateInputButton: 'vn-autocomplete[ng-model="$ctrl.stateFk"] .icons > vn-icon[icon=clear]',
saveStateButton: `${components.vnSubmit}`
saveStateButton: `button[type=submit]`
},
claimsIndex: {
searchClaimInput: `vn-claim-index ${components.vnTextfield}`,
searchClaimInput: `vn-claim-index vn-textfield input`,
searchResult: 'vn-claim-index vn-card > div > vn-table > div > vn-tbody > a',
searchButton: 'vn-claim-index vn-searchbar vn-icon[icon="search"]'
},
claimDescriptor: {
moreMenu: 'vn-claim-descriptor vn-icon-menu[vn-id="more-button"]',
moreMenu: 'vn-claim-descriptor vn-icon-menu[icon=more_vert]',
moreMenuDeleteClaim: '.vn-popover.shown .vn-drop-down li[name="Delete claim"]',
acceptDeleteClaim: 'vn-claim-descriptor > vn-confirm[vn-id="confirm-delete-claim"] button[response="ACCEPT"]'
},
@ -531,20 +529,20 @@ export default {
header: 'vn-claim-summary > vn-card > div > h5',
state: 'vn-claim-summary vn-label-value[label="State"] > section > span',
observation: 'vn-claim-summary vn-textarea[ng-model="$ctrl.summary.claim.observation"] textarea',
firstSaleItemId: 'vn-claim-summary vn-horizontal > vn-auto:nth-child(4) > vn-table > div > vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(1) > span',
firstSaleItemId: 'vn-claim-summary vn-horizontal > vn-auto:nth-child(4) vn-table > div > vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(1) > span',
firstSaleDescriptorImage: '.vn-popover.shown vn-item-descriptor img',
itemDescriptorPopover: '.vn-popover.shown vn-item-descriptor',
itemDescriptorPopoverItemDiaryButton: '.vn-popover.shown vn-item-descriptor a[href="#!/item/2/diary"]',
firstDevelopmentWorker: 'vn-claim-summary vn-horizontal > vn-auto:nth-child(5) > vn-table > div > vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(4) > span',
firstDevelopmentWorkerGoToClientButton: '.vn-popover.shown vn-worker-descriptor div.quicklinks > a[href="#!/client/21/summary"]',
firstActionTicketId: 'vn-claim-summary > vn-card > div > vn-horizontal > vn-auto:nth-child(6) > vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(2) > span',
firstDevelopmentWorker: 'vn-claim-summary vn-horizontal > vn-auto:nth-child(5) vn-table > div > vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(4) > span',
firstDevelopmentWorkerGoToClientButton: '.vn-popover.shown vn-worker-descriptor vn-quick-links > a[href="#!/client/21/summary"]',
firstActionTicketId: 'vn-claim-summary > vn-card > div > vn-horizontal > vn-auto:nth-child(6) vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(2) > span',
firstActionTicketDescriptor: '.vn-popover.shown vn-ticket-descriptor'
},
claimBasicData: {
claimStateAutocomplete: 'vn-claim-basic-data vn-autocomplete[ng-model="$ctrl.claim.claimStateFk"]',
responsabilityInputRange: 'vn-input-range',
responsabilityInputRange: 'vn-range',
observationInput: 'vn-textarea[ng-model="$ctrl.claim.observation"] textarea',
saveButton: `${components.vnSubmit}`
saveButton: `button[type=submit]`
},
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',
@ -570,7 +568,7 @@ export default {
secondClaimResponsibleAutocomplete: 'vn-claim-development vn-horizontal:nth-child(2) vn-autocomplete[ng-model="claimDevelopment.claimResponsibleFk"]',
secondClaimWorkerAutocomplete: 'vn-claim-development vn-horizontal:nth-child(2) vn-autocomplete[ng-model="claimDevelopment.workerFk"]',
secondClaimRedeliveryAutocomplete: 'vn-claim-development vn-horizontal:nth-child(2) vn-autocomplete[ng-model="claimDevelopment.claimRedeliveryFk"]',
saveDevelopmentButton: `${components.vnSubmit}`
saveDevelopmentButton: `button[type=submit]`
},
claimAction: {
importClaimButton: 'vn-claim-action vn-button[label="Import claim"]',
@ -585,9 +583,9 @@ export default {
searchResult: 'vn-order-index vn-card > div > vn-table > div > vn-tbody > a.vn-tr',
searchResultDate: 'vn-order-index vn-table vn-tbody > a:nth-child(1) > vn-td:nth-child(4)',
searchResultAddress: 'vn-order-index vn-table vn-tbody > a:nth-child(1) > vn-td:nth-child(6)',
searchOrderInput: `vn-order-index ${components.vnTextfield}`,
searchOrderInput: `vn-order-index vn-textfield input`,
searchButton: 'vn-order-index vn-searchbar vn-icon[icon="search"]',
createOrderButton: `${components.vnFloatButton}`,
createOrderButton: `vn-float-button`,
},
orderDescriptor: {
returnToModuleIndexButton: 'vn-order-descriptor a[ui-sref="order.index"]',
@ -598,7 +596,7 @@ export default {
addressAutocomplete: 'vn-autocomplete[label="Address"]',
agencyAutocomplete: 'vn-autocomplete[label="Agency"]',
landedDatePicker: 'vn-date-picker[label="Landed"]',
createButton: `${components.vnSubmit}`,
createButton: `button[type=submit]`,
cancelButton: 'vn-button[href="#!/client/index"]'
},
orderCatalog: {
@ -610,16 +608,16 @@ export default {
openTagSearch: 'vn-catalog-filter > div > vn-vertical > vn-textfield[ng-model="$ctrl.value"] .append i',
tagAutocomplete: 'vn-order-catalog-search-panel vn-autocomplete[ng-model="filter.tagFk"]',
tagValueInput: 'vn-order-catalog-search-panel vn-textfield[ng-model="filter.value"] input',
searchTagButton: 'vn-order-catalog-search-panel > div > form > vn-horizontal:nth-child(3) > vn-submit > input',
thirdFilterRemoveButton: 'vn-catalog-filter > div > vn-horizontal.chips > vn-chip:nth-child(3) button',
fourthFilterRemoveButton: 'vn-catalog-filter > div > vn-horizontal.chips > vn-chip:nth-child(4) button',
searchTagButton: 'vn-order-catalog-search-panel button[type=submit]',
thirdFilterRemoveButton: 'vn-catalog-filter .chips > vn-chip:nth-child(3) vn-icon[icon=cancel]',
fourthFilterRemoveButton: 'vn-catalog-filter .chips > vn-chip:nth-child(4) vn-icon[icon=cancel]',
},
orderBasicData: {
clientAutocomplete: 'vn-autocomplete[label="Client"]',
addressAutocomplete: 'vn-autocomplete[label="Address"]',
agencyAutocomplete: 'vn-autocomplete[label="Agency"]',
observationInput: 'vn-textarea[label="Observation"] textarea',
saveButton: `${components.vnSubmit}`,
saveButton: `button[type=submit]`,
acceptButton: 'vn-order-basic-data vn-confirm[vn-id="confirm"] button[response="ACCEPT"]'
},
orderLine: {
@ -637,7 +635,7 @@ export default {
vehicleAutoComplete: 'vn-route-create vn-autocomplete[ng-model="$ctrl.route.vehicleFk"]',
agencyAutoComplete: 'vn-route-create vn-autocomplete[ng-model="$ctrl.route.agencyModeFk"]',
descriptionInput: 'vn-route-create vn-textfield[ng-model="$ctrl.route.description"] input',
submitButton: 'vn-route-create vn-submit > input[type="submit"]'
submitButton: 'vn-route-create button[type=submit]'
},
routeDescriptor: {
volume: 'vn-route-descriptor vn-label-value[label="Volume"] > section > span'
@ -654,7 +652,7 @@ export default {
createdDateInput: 'vn-route-basic-data vn-date-picker[ng-model="$ctrl.route.created"]',
startedHourInput: 'vn-route-basic-data vn-input-time[ng-model="$ctrl.route.started"] input',
finishedHourInput: 'vn-route-basic-data vn-input-time[ng-model="$ctrl.route.finished"] input',
saveButton: 'vn-route-basic-data vn-submit[label="Save"] input'
saveButton: 'vn-route-basic-data button[type=submit]'
},
routeTickets: {
firstTicketPriority: 'vn-route-tickets vn-tr:nth-child(1) vn-textfield[ng-model="ticket.priority"] input',
@ -669,10 +667,10 @@ export default {
},
workerPbx: {
extensionInput: 'vn-worker-pbx vn-textfield[ng-model="$ctrl.worker.sip.extension"] input',
saveButton: 'vn-worker-pbx vn-submit[label="Save"] input'
saveButton: 'vn-worker-pbx button[type=submit]'
},
workerTimeControl: {
timeDialogInput: 'vn-worker-time-control > vn-dialog input',
timeDialogInput: '.vn-dialog.shown [ng-model="$ctrl.newTime"]',
mondayAddTimeButton: 'vn-worker-time-control > div > vn-card > div > vn-horizontal > vn-table > div > vn-tfoot > vn-tr:nth-child(2) > vn-td:nth-child(1) > vn-icon-button > button > vn-icon',
tuesdayAddTimeButton: 'vn-worker-time-control > div > vn-card > div > vn-horizontal > vn-table > div > vn-tfoot > vn-tr:nth-child(2) > vn-td:nth-child(2) > vn-icon-button > button > vn-icon',
wednesdayAddTimeButton: 'vn-worker-time-control > div > vn-card > div > vn-horizontal > vn-table > div > vn-tfoot > vn-tr:nth-child(2) > vn-td:nth-child(3) > vn-icon-button > button > vn-icon',
@ -721,12 +719,12 @@ export default {
navigateBackToIndex: 'vn-worker-descriptor vn-icon[icon="chevron_left"]'
},
invoiceOutIndex: {
searchInvoiceOutInput: `vn-invoice-out-index ${components.vnTextfield}`,
searchInvoiceOutInput: `vn-invoice-out-index vn-textfield input`,
searchButton: 'vn-invoice-out-index vn-searchbar vn-icon[icon="search"]',
searchResult: 'vn-invoice-out-index vn-card > div > vn-table > div > vn-tbody > a.vn-tr',
},
invoiceOutDescriptor: {
moreMenu: 'vn-invoice-out-descriptor vn-icon-menu[vn-id="more-button"]',
moreMenu: 'vn-invoice-out-descriptor vn-icon-menu[icon=more_vert]',
moreMenuDeleteInvoiceOut: '.vn-popover.shown .vn-drop-down li[name="Delete Invoice"]',
moreMenuBookInvoiceOut: '.vn-popover.shown .vn-drop-down li[name="Book invoice"]',
moreMenuShowInvoiceOutPdf: '.vn-popover.shown .vn-drop-down li[name="Show invoice PDF"]',

View File

@ -1,58 +1,35 @@
import createNightmare from '../../helpers/nightmare';
import config from '../../helpers/config.js';
describe('Login path', () => {
const nightmare = createNightmare();
it('should receive an error when the username is incorrect', async() => {
const username = 'nobody';
const password = 'nightmare';
const result = await nightmare
.goto(`${config.url}/#!/login`)
.wait(`vn-login input[name=user]`)
.write(`vn-login input[name=user]`, username)
.write(`vn-login input[name=password]`, password)
.click(`vn-login input[type=submit]`)
.doLogin('badUser', null)
.waitForLastSnackbar();
expect(result.length).toBeGreaterThan(0);
});
it('should receive an error when the username is blank', async() => {
const password = 'nightmare';
const result = await nightmare
.clearInput(`vn-login input[name=user]`)
.write(`vn-login input[name=password]`, password)
.click(`vn-login input[type=submit]`)
.doLogin('', null)
.waitForLastSnackbar();
expect(result.length).toBeGreaterThan(0);
});
it('should receive an error when the password is incorrect', async() => {
const username = 'employee';
const password = 'badpassword';
const result = await nightmare
.write(`vn-login input[name=user]`, username)
.write(`vn-login input[name=password]`, password)
.click(`vn-login input[type=submit]`)
.doLogin('employee', 'badPassword')
.waitForLastSnackbar();
expect(result.length).toBeGreaterThan(0);
});
it('should log in', async() => {
const username = 'employee';
const password = 'nightmare';
const url = await nightmare
.write(`vn-login input[name=user]`, username)
.write(`vn-login input[name=password]`, password)
.click(`vn-login input[type=submit]`)
.doLogin('employee', null)
.wait('#logout')
.parsedUrl();

View File

@ -42,9 +42,7 @@ describe('Client Edit fiscalData path', () => {
it('should not be able to edit the verified data checkbox', async() => {
const result = await nightmare
.wait(selectors.clientFiscalData.verifiedDataCheckbox)
.evaluate(selector => {
return document.querySelector(selector).getAttribute('disabled');
}, selectors.clientFiscalData.verifiedDataCheckbox);
.isDisabled(selectors.clientFiscalData.verifiedDataCheckbox);
expect(result).toBeTruthy();
});

View File

@ -16,9 +16,7 @@ describe('Client lock verified data path', () => {
const result = await nightmare
.wait(200)
.wait(selectors.clientFiscalData.verifiedDataCheckbox)
.evaluate(selector => {
return document.querySelector(selector).getAttribute('disabled');
}, selectors.clientFiscalData.verifiedDataCheckbox);
.isDisabled(selectors.clientFiscalData.verifiedDataCheckbox);
expect(result).toBeTruthy();
});

View File

@ -358,7 +358,7 @@ describe('Worker time control path', () => {
it(`should check Hank Pym doesn't have hours set on the next months first week`, async() => {
const wholeWeekHours = await nightmare
.waitToClick(selectors.workerTimeControl.nextMonthButton)
.waitToClick(selectors.workerTimeControl.nextMonthButton)
.waitForTextInElement(selectors.workerTimeControl.weekWorkedHours, '00:00 Hours')
.waitToGetProperty(selectors.workerTimeControl.weekWorkedHours, 'innerText');
expect(wholeWeekHours).toEqual('00:00 Hours');

View File

@ -30,6 +30,7 @@ describe('Ticket Edit basic data path', () => {
it(`should confirm the zone autocomplete is enabled for the role productionBoss`, async() => {
const disabled = await nightmare
.waitForSpinnerLoad()
.wait(selectors.ticketBasicData.zoneAutocomplete)
.evaluate(selector => {
return document.querySelector(selector).disabled;

View File

@ -34,7 +34,7 @@ describe('Ticket descriptor path', () => {
const result = await nightmare
.waitToClick(selectors.ticketDescriptor.moreMenu)
.waitToClick(selectors.ticketDescriptor.moreMenuChangeShippedHour)
.write(selectors.ticketDescriptor.changeShippedHourInput, '08:15')
.pickTime(selectors.ticketDescriptor.changeShippedHourInput, '08:15')
.waitToClick(selectors.ticketDescriptor.acceptChangeHourButton)
.waitForLastSnackbar();

View File

@ -17,9 +17,7 @@ describe('Ticket services path', () => {
const result = await nightmare
.waitToClick(selectors.ticketService.addServiceButton)
.wait(selectors.ticketService.firstAddDescriptionButton)
.evaluate(selector => {
return document.querySelector(selector).disabled;
}, selectors.ticketService.firstAddDescriptionButton);
.isDisabled(selectors.ticketService.firstAddDescriptionButton);
expect(result).toBeTruthy();
});

View File

@ -66,7 +66,7 @@ describe('Order catalog', () => {
const result = await nightmare
.waitToClick(selectors.orderCatalog.fourthFilterRemoveButton)
.waitToClick(selectors.orderCatalog.thirdFilterRemoveButton)
.waitForNumberOfElements('section.product', 4)
.waitForNumberOfElements('.product', 4)
.countElement('section.product');
expect(result).toEqual(4);

View File

@ -1,6 +1,6 @@
<div
class="container"
ng-click="$ctrl.onContainerMouseDown($event)"
ng-click="$ctrl.onContainerClick($event)"
ng-keydown="$ctrl.onContainerKeyDown($event)">
<div
ng-transclude="prepend"
@ -48,5 +48,5 @@
vn-id="drop-down"
on-select="$ctrl.onDropDownSelect(item)"
on-data-ready="$ctrl.onDataReady()"
on-close="$ctrl.focus()">
on-close-start="$ctrl.focus()">
</vn-drop-down>

View File

@ -228,7 +228,7 @@ export default class Autocomplete extends Field {
event.preventDefault();
}
onContainerMouseDown(event) {
onContainerClick(event) {
if (event.defaultPrevented) return;
event.preventDefault();
this.showDropDown();
@ -260,6 +260,7 @@ export default class Autocomplete extends Field {
}
showDropDown(search) {
if (this.readonly) return;
this.assignDropdownProps();
this.$.dropDown.show(this.container, search);
}

View File

@ -20,4 +20,7 @@ vn-autocomplete.vn-field {
}
}
}
&.readonly > .container > .icons.post {
display: none;
}
}

View File

@ -1,13 +0,0 @@
<div class="button-menu">
<button
class="mdl-button mdl-js-button mdl-button--raised mdl-button--colored button-menu__button">
<vn-label vn-none translate>{{::$ctrl.label}}</vn-label>
<vn-icon vn-none icon="{{::$ctrl.icon}}"></vn-icon>
<vn-icon vn-none class="button-menu__arrow_down" icon="keyboard_arrow_down"></vn-icon>
</button>
<vn-drop-down
vn-id="drop-down"
on-select="$ctrl.onDropDownSelect(item)"
ng-click="$ctrl.onDropDownClick($event)">
</vn-drop-down>
</div>

View File

@ -0,0 +1,20 @@
<button>
<span
ng-if="::$ctrl.label"
translate>
{{::$ctrl.label}}
</span>
<vn-icon
ng-if="::$ctrl.icon"
icon="{{::$ctrl.icon}}">
</vn-icon>
<vn-icon
class="button-menu__arrow_down"
icon="keyboard_arrow_down">
</vn-icon>
</button>
<vn-drop-down
vn-id="drop-down"
on-select="$ctrl.onDropDownSelect(item)"
ng-click="$ctrl.onDropDownClick($event)">
</vn-drop-down>

View File

@ -1,17 +1,13 @@
import ngModule from '../../module';
import Input from '../../lib/input';
import Button from '../button';
import assignProps from '../../lib/assign-props';
import './style.scss';
export default class ButtonMenu extends Input {
export default class ButtonMenu extends Button {
constructor($element, $scope, $transclude) {
super($element, $scope);
this.$transclude = $transclude;
this.input = this.element.querySelector('.mdl-button');
$element.on('click', e => {
if (!this.disabled)
this.onClick(e);
});
$element.on('click', e => this.onClick(e));
}
get model() {
@ -46,6 +42,7 @@ export default class ButtonMenu extends Input {
}
onClick(event) {
if (this.disabled) return;
if (event.defaultPrevented) return;
event.preventDefault();
this.emit('open');
@ -85,15 +82,14 @@ export default class ButtonMenu extends Input {
}
ButtonMenu.$inject = ['$element', '$scope', '$transclude'];
ngModule.component('vnButtonMenu', {
template: require('./button-menu.html'),
ngModule.vnComponent('vnButtonMenu', {
template: require('./index.html'),
controller: ButtonMenu,
bindings: {
label: '@',
showField: '@?',
selection: '<?',
valueField: '@?',
selectFields: '<?',
disabled: '<?',
initialData: '<?',
showFilter: '<?',
field: '=?',
@ -104,12 +100,10 @@ ngModule.component('vnButtonMenu', {
limit: '<?',
multiple: '<?',
onChange: '&?',
icon: '@?',
translateFields: '<?',
onOpen: '&?'
},
transclude: {
tplItem: '?tplItem'
},
controller: ButtonMenu
}
});

View File

@ -1,19 +1,3 @@
vn-button-menu {
position: relative;
cursor: pointer;
.button-menu__button {
padding: 0 10px;
}
vn-label {
float: left;
margin-top: 1px;
}
vn-icon {
float: left;
margin-top: 3px;
}
vn-icon.button-menu__arrow_down {
margin: 6px 0 0 5px;
}
}

View File

@ -1,6 +0,0 @@
<button type="{{::$ctrl.type}}" class="mdl-button mdl-js-button mdl-button--raised mdl-button--colored">
<span translate>{{$ctrl.label}}</span>
<vn-icon
icon="{{::$ctrl.icon}}">
</vn-icon>
</button>

View File

@ -1,34 +0,0 @@
import ngModule from '../../module';
import Input from '../../lib/input';
import './style.scss';
export default class Button extends Input {
constructor($element) {
super($element);
this.$element = $element;
this.input = this.element.querySelector('.mdl-button');
$element[0].addEventListener('click', event => {
if (this.disabled)
event.stopImmediatePropagation();
});
}
$onInit() {
if (!this.type)
this.type = 'button';
}
}
Button.$inject = ['$element'];
ngModule.component('vnButton', {
controller: Button,
template: require('./button.html'),
bindings: {
label: '@?',
disabled: '<?',
icon: '@?',
type: '@?'
}
});

View File

@ -0,0 +1,11 @@
<button type="{{::$ctrl.type}}" tabindex="-1">
<span
ng-if="::$ctrl.label"
translate>
{{::$ctrl.label}}
</span>
<vn-icon
ng-if="::$ctrl.icon"
icon="{{::$ctrl.icon}}">
</vn-icon>
</button>

View File

@ -0,0 +1,46 @@
import ngModule from '../../module';
import FormInput from '../form-input';
import './style.scss';
export default class Button extends FormInput {
constructor($element, $scope) {
super($element, $scope);
this.design = 'colored';
this.input = this.element.querySelector('button');
let element = this.element;
element.tabIndex = 0;
element.classList.add('vn-button');
this.element.addEventListener('keyup', e => this.onKeyup(e));
this.element.addEventListener('click', e => this.onClick(e));
}
$onInit() {
this.element.classList.add(this.design);
if (!this.type) this.type = 'button';
}
onKeyup(event) {
if (event.code == 'Space')
this.onClick(event);
}
onClick(event) {
if (event.defaultPrevented) return;
// event.preventDefault();
// FIXME: Don't stop event propagation
if (this.disabled) event.stopImmediatePropagation();
}
}
Button.$inject = ['$element', '$scope'];
ngModule.vnComponent('vnButton', {
controller: Button,
template: require('./index.html'),
bindings: {
icon: '@?',
type: '@?'
}
});

View File

@ -1,5 +1,83 @@
vn-button {
& > button > vn-icon {
vertical-align: middle;
@import "variables";
.vn-button {
display: inline-flex;
align-items: center;
justify-content: center;
height: 36px;
border: none;
border-radius: .1em;
font-family: vn-font-bold;
text-transform: uppercase;
font-size: 14px;
cursor: pointer;
box-sizing: border-box;
outline: none;
& > button {
width: 100%;
padding: 0 12px;
box-sizing: border-box;
background-color: transparent;
border: none;
height: inherit;
color: inherit;
font: inherit;
display: block;
text-transform: inherit;
cursor: inherit;
outline: none;
display: flex;
align-items: center;
justify-content: center;
& > vn-icon {
vertical-align: middle;
color: inherit;
font-size: 1.7em;
}
}
}
&.colored {
color: white;
background-color: $color-main;
box-shadow: 0 .15em .15em 0 rgba(0, 0, 0, .3);
transition: background 200ms ease-in-out;
&:not(.disabled) {
&:hover,
&:focus {
background-color: lighten($color-main, 10%);
}
}
}
&.flat {
color: $color-main;
background-color: transparent;
box-shadow: none;
transition: background 200ms ease-in-out;
&:not(.disabled) {
&:hover,
&:focus {
background-color: $color-hover-cd;
}
}
}
&:hover,
&:focus {
outline: none;
}
&.round {
border-radius: 50%;
height: 3.8em;
width: 3.8em;
& > button > span {
display: none;
}
}
&.disabled {
opacity: .7;
cursor: initial;
}
}

View File

@ -7,7 +7,7 @@ export default function directive() {
transclude: true,
template: require('./card.html'),
link: function($scope, $element, $attrs, $ctrl, $transclude) {
$element.addClass('demo-card-wide mdl-shadow--2dp bg-panel');
$element.addClass('demo-card-wide vn-shadow bg-panel');
$transclude($scope, function(clone) {
angular.element($element[0].querySelector('div')).append(clone);

View File

@ -1,3 +1,4 @@
vn-card {
display: block;
box-sizing: border-box;
}

View File

@ -1,8 +1,7 @@
<vn-one>
<span ng-class="{'mdl-chip--deletable': !$ctrl.disabled}" class="mdl-chip">
<span class="mdl-chip__text ellipsize" ng-transclude></span>
<button ng-click="$ctrl.remove()" ng-show="!$ctrl.disabled" type="button" class="mdl-chip__action">
<i class="material-icons">cancel</i>
</button>
</span>
</vn-one>
<div ng-transclude></div>
<vn-icon
ng-click="$ctrl.onRemove()"
ng-if="$ctrl.removable"
icon="cancel"
tabindex="0">
</vn-icon>

View File

@ -1,17 +1,12 @@
import ngModule from '../../module';
import Component from '../../lib/component';
import './style.scss';
export default class Chip {
/**
* Remove chip event
*/
remove() {
if (this.onRemove)
this.onRemove();
export default class Chip extends Component {
onRemove() {
if (!this.disabled) this.emit('remove');
}
}
Chip.$inject = ['$element', '$scope', '$transclude'];
ngModule.component('vnChip', {
@ -20,6 +15,6 @@ ngModule.component('vnChip', {
transclude: true,
bindings: {
disabled: '<?',
onRemove: '&?'
removable: '<?'
}
});

View File

@ -16,13 +16,13 @@ describe('Component vnChip', () => {
controller = $componentController('vnChip', {$element, $scope, $transclude: () => {}});
}));
describe('remove()', () => {
it(`should call onRemove()`, () => {
controller.onRemove = () => {};
spyOn(controller, 'onRemove');
controller.remove();
describe('onRemove()', () => {
it(`should emit remove event`, () => {
controller.emit = () => {};
spyOn(controller, 'emit');
controller.onRemove();
expect(controller.onRemove).toHaveBeenCalledWith();
expect(controller.emit).toHaveBeenCalledWith('remove');
});
});
});

View File

@ -1,18 +1,53 @@
@import "variables";
vn-chip {
border-radius: 16px;
background-color: $color-bg;
margin: 0 0.5em 0.5em 0;
color: $color-font;
font-size: 14px;
margin: .25em;
display: inline-flex;
align-items: center;
text-overflow: ellipsis;
white-space: nowrap;
height: 28px;
padding: 0 .7em;
overflow: hidden;
.mdl-chip {
background-color: rgba($color-main, 0.9);
color: #FFF
&.colored {
background-color: $color-main;
color: $color-font-dark;
}
.mdl-chip:active {
background-color: $color-main
}
& > vn-one > span > span {
& > div {
display: flex;
align-items: center;
max-width: 100%;
height: 100%;
& > vn-avatar {
margin-left: -0.7em;
margin-right: .4em;
}
}
& > vn-icon {
margin-left: .2em;
margin-right: -0.3em;
vertical-align: middle;
opacity: .6;
cursor: pointer;
transition: opacity 250ms ease-out;
&:hover,
&:focus {
opacity: 1;
}
}
}
vn-avatar {
display: inline-block;
height: 28px;
width: 28px;
border-radius: 50%;
}

View File

@ -1,8 +0,0 @@
<span
ng-class="{'pointer': $ctrl.$attrs['onClick']}"
class="mdl-chip mdl-chip--contact"
ng-repeat="legend in $ctrl.data track by $index"
ng-click="$ctrl.onClick(legend)">
<span class="mdl-chip__contact" ng-style="{backgroundColor: legend.color}"></span>
<span class="mdl-chip__text">{{legend.name}}</span>
</span>

View File

@ -1,24 +0,0 @@
import ngModule from '../../module';
import Component from '../../lib/component';
import './style.scss';
export default class Controller extends Component {
constructor($element, $scope, $attrs) {
super($element, $scope);
this.$attrs = $attrs;
}
onClick(legend) {
this.emit('click', {legend});
}
}
Controller.$inject = ['$element', '$scope', '$attrs'];
ngModule.component('vnColorLegend', {
template: require('./index.html'),
controller: Controller,
bindings: {
data: '<?'
}
});

View File

@ -1,13 +0,0 @@
@import "variables";
.mdl-chip--contact {
margin-left: 5px;
height: 20px;
line-height: 5px;
float: left
}
.mdl-chip--contact .mdl-chip__contact {
height: 20px;
width: 20px
}

View File

@ -1,15 +1,40 @@
import ngModule from '../../module';
import Field from '../field';
import {Flatpickr} from '../../vendor';
import './style.scss';
class DatePicker extends Field {
constructor($element, $scope, $compile, $translate) {
constructor($element, $scope, $compile, $translate, $filter) {
super($element, $scope, $compile);
this.$translate = $translate;
this.$filter = $filter;
this.input = $compile(`<input type="text"></input>`)($scope)[0];
this.initPicker();
this.input = $compile(`<input type="date"></input>`)($scope)[0];
this.input.addEventListener('change', () => this.onValueUpdate());
}
onValueUpdate() {
let date = null;
let value = this.input.value;
if (value) {
date = new Date(value);
if (this.field) {
let orgDate = this.field instanceof Date
? this.field
: new Date(this.field);
date.setHours(
orgDate.getHours(),
orgDate.getMinutes(),
orgDate.getSeconds(),
orgDate.getMilliseconds()
);
}
}
super.field = date;
this.$.$applyAsync();
}
get field() {
@ -18,69 +43,10 @@ class DatePicker extends 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();
this.input.value = this.$filter('date')(value, 'yyyy-MM-dd');
}
}
DatePicker.$inject = ['$element', '$scope', '$compile', '$translate'];
DatePicker.$inject = ['$element', '$scope', '$compile', '$translate', '$filter'];
ngModule.vnComponent('vnDatePicker', {
controller: DatePicker,
@ -88,12 +54,3 @@ ngModule.vnComponent('vnDatePicker', {
options: '<?'
}
});
function fixDate(date, mult = 1) {
if (date) {
let offset = date.getTimezoneOffset() * 60000;
date.setTime(date.getTime() + (offset * mult));
}
return date;
}

View File

@ -2,7 +2,6 @@ describe('Component vnDatePicker', () => {
let $filter;
let $element;
let $ctrl;
let today;
beforeEach(angular.mock.module('vnCore', $translateProvider => {
$translateProvider.translations('en', {});
@ -13,9 +12,6 @@ describe('Component vnDatePicker', () => {
$element = $compile(`<vn-date-picker></vn-date-picker>`)($rootScope);
$ctrl = $element.controller('vnDatePicker');
today = new Date();
today.setUTCHours(0, 0, 0, 0);
}));
afterEach(() => {
@ -24,20 +20,12 @@ describe('Component vnDatePicker', () => {
describe('field() setter', () => {
it(`should display the formated the date`, () => {
let today;
today = new Date();
today.setHours(0, 0, 0, 0);
$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');
let displayed = $filter('date')(today, 'yyyy-MM-dd');
expect($ctrl.value).toEqual(displayed);
});

View File

@ -1,7 +1,8 @@
<vn-popover
vn-id="popover"
on-open="$ctrl.onOpen()"
on-close="$ctrl.onClose()">
on-close="$ctrl.onClose()"
on-close-start="$ctrl.emit('closeStart')">
<div class="vn-drop-down">
<div ng-show="$ctrl.showFilter" class="filter">
<vn-textfield

View File

@ -193,7 +193,7 @@ export default class DropDown extends Component {
onOpen() {
this.document.addEventListener('keydown', this.docKeyDownHandler);
this.$.list.scrollTop = 0;
this.$.input.focus();
setTimeout(() => this.$.input.focus());
this.emit('open');
}

View File

@ -11,7 +11,6 @@ export default class Field extends FormInput {
this.suffix = null;
this.control = this.element.querySelector('.control');
this.classList = this.element.classList;
this.classList.add('vn-field');
this.element.addEventListener('click', e => this.onClick(e));
@ -43,9 +42,11 @@ export default class Field extends FormInput {
}
set input(value) {
if (this.input) this.control.removeChild(this.input);
if (this.input)
this.control.removeChild(this.input);
this._input = value;
this.control.appendChild(value);
if (value)
this.control.appendChild(value);
}
get input() {
@ -84,36 +85,8 @@ export default class Field extends FormInput {
return this.input.placeholder;
}
set tabIndex(value) {
this.input.tabIndex = value;
}
get tabIndex() {
return this.input.tabIndex;
}
set disabled(value) {
this._disabled = boolTag(value);
this.input.disabled = this._disabled;
this.classList.toggle('disabled', this._disabled);
}
get disabled() {
return this._disabled;
}
set readonly(value) {
this._readonly = boolTag(value);
this.input.readOnly = this._readonly;
this.classList.toggle('readonly', this._readonly);
}
get readonly() {
return this._readonly;
}
set required(value) {
this._required = boolTag(value);
this._required = value;
let required = this.element.querySelector('.required');
display(required, this._required);
}
@ -180,9 +153,13 @@ export default class Field extends FormInput {
fix.innerText = text || '';
}
refreshTabIndex() {
this.input.tabIndex = this.disabled ? -1 : this.tabIndex;
}
onClick() {
if (event.defaultPrevented) return;
event.preventDefault();
// if (event.defaultPrevented) return;
// event.preventDefault();
if (this.input !== document.activeElement)
this.focus();
@ -250,15 +227,10 @@ ngModule.vnComponent('vnField', {
suffix: '@?',
hint: '@?',
error: '<?',
tabIndex: '<?',
rule: '@?'
}
});
function boolTag(value) {
return Boolean(value || value === '');
}
function display(element, display) {
element.style.display = display ? 'initial' : 'none';
}

View File

@ -35,7 +35,7 @@
& > .fix {
padding-top: 24px;
line-height: 24px;
font-size: $input-font-size;
font-size: $font-size;
opacity: 0;
transition: opacity 200ms ease-in-out;
@ -58,18 +58,39 @@
border: none;
font-family: Arial, sans-serif;
display: block;
font-size: $input-font-size;
font-size: $font-size;
width: 100%;
background: 0;
color: inherit;
box-sizing: border-box;
min-height: 56px;
}
& > input {
position: relative;
&[type=time],
&[type=date],
&[type=password] {
opacity: 0;
transition: opacity 200ms ease-in-out;
cursor: pointer;
}
&[type=time],
&[type=date] {
clip-path: inset(0 20px 0 0);
opacity: 0;
transition: opacity 200ms ease-in-out;
&::-webkit-inner-spin-button,
&::-webkit-clear-button {
display: none;
-webkit-appearance: none;
}
&::-webkit-calendar-picker-indicator {
position: absolute;
height: 100%;
width: 100%;
opacity: 0;
cursor: pointer;
}
}
&[type=number] {
-moz-appearance: textfield;
@ -83,6 +104,15 @@
&:invalid {
box-shadow: none;
}
&:-internal-autofill-selected {
&,
&:hover,
&:focus,
&:active,
&:valid {
box-shadow: 0 0 0 40px $color-bg-panel inset;
}
}
}
}
}
@ -172,7 +202,8 @@
}
& > .control > * {
&[type=time],
&[type=date] {
&[type=date],
&[type=password] {
opacity: 1;
}
}
@ -214,7 +245,6 @@
}
}
& > .hint {
z-index: -1;
padding: 4px 0;
height: 12px;
color: rgba(0, 0, 0, .4);
@ -224,11 +254,12 @@
transition-duration: 200ms;
transition-timing-function: ease-in-out;
opacity: 0;
visibility: hidden;
&.filled {
z-index: 0;
opacity: 1;
transform: translateY(0);
visibility: visible;
}
}
&.invalid {

View File

@ -1,3 +0,0 @@
<button class="mdl-button mdl-js-button mdl-button--fab mdl-js-ripple-effect mdl-button--colored">
<vn-icon icon="{{::$ctrl.icon}}"></vn-icon>
</button>

View File

@ -1,8 +0,0 @@
import ngModule from '../../module';
ngModule.component('vnFloatButton', {
template: require('./float-button.html'),
bindings: {
icon: '@'
}
});

View File

@ -0,0 +1,13 @@
import ngModule from '../../module';
import Button from '../button';
export default class FloatButton extends Button {
constructor($element, $scope) {
super($element, $scope);
this.element.classList.add('round');
}
}
ngModule.vnComponent('vnFloatButton', {
controller: FloatButton
});

View File

@ -9,6 +9,11 @@ import Component from '../../lib/component';
* @property {Boolean} disabled Put component in disabled mode
*/
export default class FormInput extends Component {
constructor($element, $scope) {
super($element, $scope);
this.classList = this.element.classList;
}
$onInit() {
// XXX: Compatibility with old inputs
let attrs = this.$element[0].attributes;
@ -41,6 +46,48 @@ export default class FormInput extends Component {
get name() {
return this.element.getAttribute('name');
}
set disabled(value) {
this._disabled = boolTag(value);
this.input.disabled = this._disabled;
this.classList.toggle('disabled', this._disabled);
this.refreshTabIndex();
}
get disabled() {
return this._disabled;
}
set readonly(value) {
this._readonly = boolTag(value);
this.input.readOnly = this._readonly;
this.classList.toggle('readonly', this._readonly);
}
get readonly() {
return this._readonly;
}
set tabIndex(value) {
this._tabIndex = value;
this.refreshTabIndex();
}
get tabIndex() {
return this._tabIndex;
}
select() {
this.input.select();
}
focus() {
this.input.focus();
}
refreshTabIndex() {
this.element.tabIndex = this.disabled ? -1 : this.tabIndex;
}
}
ngModule.vnComponent('vnFormInput', {
@ -50,9 +97,14 @@ ngModule.vnComponent('vnFormInput', {
field: '=?',
name: '@?',
disabled: '<?',
readonly: '<?'
readonly: '<?',
tabIndex: '<?'
},
require: {
ngModel: '?ngModel'
}
});
function boolTag(value) {
return Boolean(value || value === '');
}

View File

@ -1,3 +0,0 @@
<button type="button" ng-disabled="$ctrl.disabled">
<vn-icon icon="{{::$ctrl.icon}}">
</button>

View File

@ -1,39 +0,0 @@
import ngModule from '../../module';
import './style.scss';
export default class IconButton {
constructor($element) {
this.element = $element[0];
if (this.element.getAttribute('tabindex') == null)
this.element.tabIndex = 0;
this.element.addEventListener('keyup', e => this.onKeyup(e));
this.element.addEventListener('click', e => this.onClick(e));
}
onKeyup(event) {
if (event.code == 'Space')
this.onClick(event);
}
onClick(event) {
if (event.defaultPrevented) return;
event.preventDefault();
// FIXME: Don't use Event.stopPropagation()
let button = this.element.querySelector('button');
if (this.disabled || button.disabled)
event.stopImmediatePropagation();
}
}
IconButton.$inject = ['$element'];
ngModule.component('vnIconButton', {
controller: IconButton,
template: require('./icon-button.html'),
bindings: {
icon: '@',
disabled: '<?'
}
});

View File

@ -0,0 +1,14 @@
import ngModule from '../../module';
import Button from '../button';
import './style.scss';
export default class IconButton extends Button {
constructor($element, $scope) {
super($element, $scope);
this.design = null;
}
}
ngModule.vnComponent('vnIconButton', {
controller: IconButton
});

View File

@ -2,27 +2,12 @@
vn-icon-button {
@extend %clickable-light;
outline: 0;
color: $color-main;
display: inline-flex;
align-items: center;
font-size: 18pt;
padding: .25em;
& > button {
background-color: transparent;
display: block;
color: inherit;
border: 0;
padding: 0;
font-size: inherit;
&:hover {
background-color: initial;
}
& > vn-icon {
display: block;
font-size: inherit;
}
& > button {
padding: .2em !important;
}
&:focus {
opacity: .6;
}
}

View File

@ -1 +0,0 @@
<vn-icon icon="{{::$ctrl.icon}}"></vn-icon>

View File

@ -1,29 +0,0 @@
import ngModule from '../../module';
import './style.scss';
export default class IconFocusable {
constructor($element) {
$element[0].tabIndex = 0;
$element.on("keyup", event => this.onKeyDown(event, $element));
}
onKeyDown(event, $element) {
if (event.defaultPrevented) return;
if (event.keyCode == 32 || event.keyCode == 13) {
event.preventDefault();
$element.triggerHandler('click');
}
}
}
IconFocusable.$inject = ['$element'];
ngModule.component('vnIconFocusable', {
controller: IconFocusable,
template: require('./icon-focusable.html'),
bindings: {
icon: '@',
className: '@?',
enabled: '<?',
label: '@?'
}
});

View File

@ -1,10 +0,0 @@
vn-icon-focusable {
display: inline-block;
text-align: center;
& > i,
& > i.material-icons {
display: block;
font-size: inherit;
}
}

View File

@ -1,11 +0,0 @@
<div class="icon-menu">
<vn-icon
class="button"
icon="{{::$ctrl.icon}}">
</vn-icon>
<vn-drop-down
vn-id="drop-down"
on-select="$ctrl.onDropDownSelect(item)"
ng-click="$ctrl.onDropDownClick($event)">
</vn-drop-down>
</div>

View File

@ -1,41 +0,0 @@
import ngModule from '../../module';
import ButtonMenu from '../button-menu/button-menu';
import './style.scss';
export default class IconMenu extends ButtonMenu {
constructor($element, $scope, $transclude) {
super($element, $scope);
this.$transclude = $transclude;
this.input = this.element.querySelector('.button');
}
}
IconMenu.$inject = ['$element', '$scope', '$transclude'];
ngModule.component('vnIconMenu', {
template: require('./icon-menu.html'),
bindings: {
label: '@',
showField: '@?',
selection: '<?',
valueField: '@?',
selectFields: '<?',
disabled: '<?',
initialData: '<?',
showFilter: '<?',
field: '=?',
url: '@?',
data: '<?',
where: '@?',
order: '@?',
limit: '<?',
multiple: '<?',
onChange: '&?',
icon: '@?',
translateFields: '<?',
onOpen: '&?'
},
transclude: {
tplItem: '?tplItem'
},
controller: IconMenu
});

View File

@ -0,0 +1,11 @@
<button>
<vn-icon
class="button"
icon="{{::$ctrl.icon}}">
</vn-icon>
</button>
<vn-drop-down
vn-id="drop-down"
on-select="$ctrl.onDropDownSelect(item)"
ng-click="$ctrl.onDropDownClick($event)">
</vn-drop-down>

View File

@ -0,0 +1,14 @@
import ngModule from '../../module';
import ButtonMenu from '../button-menu';
export default class IconMenu extends ButtonMenu {
constructor($element, $scope) {
super($element, $scope);
this.element.classList.add('flat');
}
}
ngModule.vnComponent('vnIconMenu', {
template: require('./index.html'),
controller: IconMenu
});

View File

@ -1,8 +0,0 @@
vn-icon-menu {
cursor: pointer;
vn-drop-down {
font-family: 'vn-font';
outline: 0
}
}

View File

@ -10,36 +10,35 @@ import './subtitle/subtitle';
import './spinner/spinner';
import './snackbar/snackbar';
import './tooltip/tooltip';
import './icon-menu/icon-menu';
import './button-menu/button-menu';
import './popover/popover';
import './drop-down/drop-down';
import './menu/menu';
import './multi-check/multi-check';
import './button/button';
import './icon-button/icon-button';
import './submit/submit';
import './card/card';
import './float-button/float-button';
import './step-control/step-control';
import './label-value/label-value';
import './pagination/pagination';
import './searchbar/searchbar';
import './scroll-up/scroll-up';
import './autocomplete';
import './button';
import './button-menu';
import './calendar';
import './check';
import './chip';
import './color-legend';
import './data-viewer';
import './date-picker';
import './field';
import './float-button';
import './icon-menu';
import './icon-button';
import './input-number';
import './input-range';
import './range';
import './input-time';
import './input-file';
import './list';
import './radio';
import './submit';
import './table';
import './td-editable';
import './textarea';

View File

@ -1,42 +1,53 @@
<div class="container"
ng-class="{selected: $ctrl.hasFocus}">
<div class="textField">
<div class="leftIcons" ng-transclude="leftIcons"></div>
<div class="infix">
<section class="value" ng-click="$ctrl.openFileSelector()" translate>
<div class="container">
<div
ng-transclude="prepend"
class="prepend">
</div>
<div class="infix">
<div class="fix prefix"></div>
<div class="control">
<section
class="value"
ng-click="$ctrl.openFileSelector()"
translate>
{{$ctrl.value}}
</section>
<input
class="mdl-textfield__input"
type="file"
name="{{::$ctrl.name}}"
ng-model="$ctrl.files"
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}}"
accept="{{$ctrl.accept}}"/>
<label class="label">
<span translate>{{::$ctrl.label}}</span>
<span translate ng-show="::$ctrl.required">*</span>
</label>
type="file"
ng-model="$ctrl.files"
accept="{{$ctrl.accept}}">
</input>
</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>
<vn-icon-button
icon="cloud_upload"
vn-tooltip="Select a file"
ng-click="$ctrl.openFileSelector()">
</vn-icon-button>
</div>
<div class="rightIcons" ng-transclude="rightIcons"></div>
<div class="fix suffix"></div>
<label>
<span translate>{{::$ctrl.label}}</span>
<span class="required">*</span>
</label>
</div>
<div class="icons pre">
<vn-icon
icon="clear"
translate-attr="{title: 'Clear'}"
ng-click="$ctrl.onClear($event)">
</vn-icon>
<vn-icon
icon="cloud_upload"
vn-tooltip="Select a file"
ng-click="$ctrl.openFileSelector()">
</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="icons post">
</div>
<div class="underline blur"></div>
<div class="underline focus"></div>
</div>
<div class="hint"></div>

View File

@ -1,15 +1,13 @@
import ngModule from '../../module';
import Input from '../../lib/input';
import FormInput from '../form-input';
import './style.scss';
export default class InputFile extends Input {
export default class InputFile extends FormInput {
constructor($element, $scope) {
super($element, $scope);
this.element = $element[0];
this.hasFocus = false;
this._multiple = false;
this._value = 'Select a file';
this.input = this.element.querySelector('input');
this.registerEvents();
}
@ -106,26 +104,12 @@ export default class InputFile extends Input {
}
}
InputFile.$inject = ['$element', '$scope'];
ngModule.component('vnInputFile', {
ngModule.vnComponent('vnInputFile', {
template: require('./index.html'),
controller: InputFile,
transclude: {
leftIcons: '?tLeftIcons',
rightIcons: '?tRightIcons'
},
bindings: {
label: '@?',
name: '@?',
disabled: '<?',
multiple: '<?',
required: '@?',
accept: '@?',
rule: '@?',
files: '=model',
validate: '&',
onChange: '&',
onClear: '&'
files: '=model'
}
});

View File

@ -7,159 +7,7 @@ vn-input-file {
padding: 4px 0;
outline: 0
}
input {
display: none !important
}
margin: 20px 0;
display: inline-block;
width: 100%;
& > .container {
width: 100%;
position: relative;
padding-bottom: 2px;
display: flex;
& > .textField {
width: 100%;
display: flex;
align-items: center;
position: relative;
padding-top: 4px;
}
}
.leftIcons, .rightIcons, .suffix {
display: flex;
color: $color-font-secondary;
.material-icons {
font-size: 20px !important
}
}
.suffix vn-icon-button {
padding: 0
}
t-left-icons {
padding-right: 0.5em
}
t-right-icons {
padding-left: 0.5em
}
.infix {
position: relative;
display: block;
flex: auto;
width: 100%;
min-width: 0;
}
i.clear {
visibility: hidden;
cursor: pointer;
outline: 0;
&:hover {
color: #222;
}
}
&:hover i.clear {
visibility: visible;
}
i.visible {
visibility: visible;
}
label {
position: absolute;
bottom: 0;
left: 0;
padding: 4px 0!important;
pointer-events: none;
color: $color-font-secondary;
transition-duration: .2s;
transition-timing-function: cubic-bezier(.4,0,.2,1);
}
&.not-empty label{
bottom: 24px;
color: $color-main;
padding: 0;
font-size: 12px;
}
input {
outline: none;
border: none;
font-family: "Helvetica", "Arial", sans-serif;
display: block;
font-size: 16px;
width: 100%;
background: 0 0;
color: inherit;
padding: 4px;
box-sizing: border-box;
border-bottom: 0!important;
&[type=number] {
-moz-appearance: textfield;
&::-webkit-outer-spin-button,
&::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
}
&:invalid {
box-shadow: none;
}
}
.underline {
position: absolute;
bottom: 0;
height: 1px;
content: ' ';
pointer-events: none;
width: 100%;
background-color: $color-input-underline;
}
.selected.underline {
background-color: $color-main;
height: 2px;
left: 50%;
width: 0px !important;
transition-duration: 0.2s;
transition-timing-function: cubic-bezier(.4,0,.2,1);
}
div.selected {
&.container{
border-bottom: 0px;
}
label {
bottom: 24px;
color: $color-main;
font-size: 12px;
}
.selected.underline{
left: 0;
width: 100%!important;
}
}
& > div.container > div.textField > div.infix.invalid {
@extend div.selected;
& > span.mdl-textfield__error {
visibility: visible;
}
& > label {
color: #d50000;
}
}
.infix.invalid + .underline {
background-color: #d50000;
}
label span:nth-child(2) {
color: $color-alert
input[type=file] {
display: none;
}
}

View File

@ -1,9 +0,0 @@
<div>
<label translate>{{::$ctrl.label}}</label>
<input
name="{{$ctrl.name}}"
class="mdl-slider mdl-js-slider"
type="range"/>
<label class="min-label" translate>Company</label>
<label class="max-label" translate>Sales/Client</label>
</div>

View File

@ -1,79 +0,0 @@
import ngModule from '../../module';
import Input from '../../lib/input';
import './style.scss';
export default class inputRange extends Input {
constructor($element, $scope) {
super($element, $scope);
this.mdlElement = this.element.querySelector('.mdl-slider');
componentHandler.upgradeElement(this.mdlElement);
this.mdlElement.addEventListener('change', () => {
this._value = this.input.value;
this.$.$applyAsync();
if (this._value && this.onChange)
this.emit('change', {value: this._value});
});
}
get value() {
return this._value;
}
set value(value) {
this._value = value;
this.mdlElement.MaterialSlider.change(value);
}
get max() {
return this.input.max;
}
set max(value) {
this.input.max = value;
}
get min() {
return this.input.min;
}
set min(value) {
this.input.min = value;
}
get step() {
return this.input.step;
}
set step(value) {
this.input.step = value;
}
get() {
return this._model;
}
set model(value) {
this._model = value;
}
set disabled(value) {
this.input.disabled = value;
}
}
inputRange.$inject = ['$element', '$scope'];
ngModule.component('vnInputRange', {
template: require('./index.html'),
controller: inputRange,
bindings: {
label: '@?',
disabled: '<?',
min: '<?',
max: '<?',
step: '<?',
value: '=',
model: '=',
onChange: '&'
}
});

View File

@ -1,14 +0,0 @@
@import "variables";
vn-input-range {
label {
color: $color-main;
font-size: 12px;
padding: 0 25px;
}
label.min-label, label.max-label {
color: $color-font;
}
label.max-label {
float: right;
}
}

View File

@ -15,7 +15,7 @@ export default class InputTime extends Field {
}
set field(value) {
this.input.value = this.$filter('dateTime')(value, 'HH:mm');
this.input.value = this.$filter('date')(value, 'HH:mm');
super.field = value;
}
@ -25,7 +25,10 @@ export default class InputTime extends Field {
if (value) {
let split = value.split(':').map(i => parseInt(i) || null);
date = new Date(this.field || null);
date = this.field instanceof Date
? this.field
: new Date(this.field || null);
date.setHours(split[0], split[1], 0, 0);
}

View File

@ -24,7 +24,7 @@ describe('Component vnInputTime', () => {
it(`should display the formated the date`, () => {
let date = new Date();
$ctrl.field = date;
let displayed = $filter('dateTime')(date, 'HH:mm');
let displayed = $filter('date')(date, 'HH:mm');
expect($ctrl.value).toEqual(displayed);
});

View File

@ -24,11 +24,10 @@
vn-icon-button {
opacity: .4;
color: $color-main;
margin-left: .5em;
transition: opacity 250ms ease-out;
padding: 0;
font-size: 2em;
font-size: 1.2em;
&:hover {
opacity: 1;

View File

@ -1,5 +1,5 @@
import ngModule from '../../module';
import Input from '../../lib/input';
import FormInput from '../form-input';
import './style.scss';
/**
@ -8,7 +8,7 @@ import './style.scss';
* @param {Array} data List of options shown in drop-down
* @param {Array} models Elements to check / unCheck
*/
export default class MultiCheck extends Input {
export default class MultiCheck extends FormInput {
constructor($element, $scope) {
super($element, $scope);
this._checked = false;

View File

@ -109,6 +109,7 @@ 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,7 +119,7 @@ export default class Popover extends Component {
this.bgMouseDownHandler = null;
if (this.deregisterCallback) this.deregisterCallback();
this.emit('close');
this.emit('closeStart');
}
/**

View File

@ -0,0 +1,4 @@
<label class="main" translate>{{::$ctrl.label}}</label>
<input name="{{::$ctrl.name}}" type="range"></input>
<label class="min-label" translate>{{::$ctrl.minLabel}}</label>
<label class="max-label" translate>{{::$ctrl.maxLabel}}</label>

View File

@ -0,0 +1,50 @@
import ngModule from '../../module';
import FormInput from '../form-input';
import './style.scss';
export default class Range extends FormInput {
constructor($element, $scope) {
super($element, $scope);
this.input = this.element.querySelector('input');
}
get max() {
return this.input.max;
}
set max(value) {
this.input.max = value;
}
get min() {
return this.input.min;
}
set min(value) {
this.input.min = value;
}
get step() {
return this.input.step;
}
set step(value) {
this.input.step = value;
}
refreshTabIndex() {
this.input.tabIndex = this.disabled ? -1 : this.tabIndex;
}
}
ngModule.vnComponent('vnRange', {
template: require('./index.html'),
controller: Range,
bindings: {
min: '<?',
max: '<?',
step: '<?',
minLabel: '@?',
maxLabel: '@?'
}
});

View File

@ -0,0 +1,84 @@
@import "variables";
@mixin range($thumb-selector, $track-selector) {
&::#{$thumb-selector} {
-webkit-appearance: none;
margin-top: -5px;
border-radius: 50%;
background: $color-main;
border: none;
height: 12px;
width: 12px;
border-radius: 50%;
transition-property: transform, box-shadow;
transition-duration: 250ms;
transition-timing-function: ease-out;
}
&:focus::#{$thumb-selector} {
box-shadow: 0 0 0 10px rgba($color-main, .2);
}
&:active::#{$thumb-selector} {
transform: scale(1.5);
box-shadow: none;
}
&:disabled::#{$thumb-selector} {
transform: none;
cursor: initial;
}
&::#{$track-selector} {
width: 100%;
height: 3px;
cursor: inherit;
background: $color-secondary;
border-radius: 2px;
border: none;
}
}
vn-range {
& > label {
font-size: 12px;
&.main {
color: $color-main;
}
&.min-label {
float: left;
}
&.max-label {
float: right;
}
}
& > input {
cursor: pointer;
height: 30px;
display: block;
width: 100%;
background: transparent;
border-color: transparent;
-webkit-appearance: none;
margin: .2em 0;
&:focus {
outline: none;
}
&::-moz-focus-outer {
border: 0;
}
@include range(
"-moz-range-thumb",
"-moz-range-track"
);
@include range(
"-webkit-slider-thumb",
"-webkit-slider-runnable-track"
);
@include range(
"-ms-thumb",
"-ms-track"
);
&:disabled {
cursor: initial;
}
}
}

View File

@ -1,5 +1,6 @@
<button class="mdl-button mdl-js-button mdl-button--fab mdl-button--mini-fab mdl-js-ripple-effect mdl-button--colored"
<vn-button
icon="keyboard_arrow_up"
ng-click="$ctrl.goUp()"
vn-tooltip="Go up">
<vn-icon icon="keyboard_arrow_up"></vn-icon>
</button>
vn-tooltip="Go up"
class="round">
</vn-button>

View File

@ -1,6 +1,6 @@
vn-scroll-up {
top: 5em;
right: 2.5em;
top: 5.5em;
right: 2em;
display: none;
position: fixed;
}

View File

@ -1,6 +1,6 @@
<form ng-submit="$ctrl.onSubmit()">
<vn-textfield
class="dense vn-py-md"
class="dense"
placeholder="{{::'Search' | translate}}"
ng-model="$ctrl.searchString">
<prepend>

View File

@ -69,7 +69,7 @@ export default class Controller extends Component {
this.$panelScope = this.$.$new();
this.$panel = this.$compile(`<${this.panel}/>`)(this.$panelScope);
let panel = this.$panel.isolateScope().$ctrl;
let panel = this.$panel[0].$ctrl;
if (this.shownFilter)
panel.filter = JSON.parse(JSON.stringify(this.shownFilter));
panel.onSubmit = filter => this.onPanelSubmit(filter);

View File

@ -2,6 +2,7 @@
vn-searchbar {
display: block;
width: 100%;
}
.search-panel {

View File

@ -1,2 +1,12 @@
<div class="mdl-spinner mdl-spinner--single-color mdl-js-spinner">
<div class="loader">
<svg class="circular" viewBox="25 25 50 50">
<circle
class="path"
cx="50"
cy="50"
r="20"
fill="none"
stroke-miterlimit="10">
</circle>
</svg>
</div>

View File

@ -1,19 +1,18 @@
import ngModule from '../../module';
import Component from '../../lib/component';
import './style.css';
import './style.scss';
/**
* A spinner to inform the user about loading process.
*/
export default class Spinner extends Component {
constructor($element, $scope) {
super($element);
super($element, $scope);
this._enable = false;
this.spinner = $element[0].firstChild;
componentHandler.upgradeElement(this.spinner);
}
/**
* Enables/disables the spinner.
* Activates/deactivates the spinner.
*
* @param {Boolean} value %true to enable, %false to disable
*/
@ -35,14 +34,14 @@ export default class Spinner extends Component {
* Activates the spinner.
*/
start() {
this.spinner.MaterialSpinner.start();
this.spinner.style.display = 'block';
this._enable = true;
}
/**
* Deactivates the spinner.
*/
stop() {
this.spinner.MaterialSpinner.stop();
this.spinner.style.display = 'none';
this._enable = false;
}
}

View File

@ -1,7 +1,6 @@
import './spinner.js';
describe('Component vnSpinner', () => {
let $scope;
let $element;
let controller;
@ -9,53 +8,44 @@ describe('Component vnSpinner', () => {
$translateProvider.translations('en', {});
}));
beforeEach(angular.mock.inject(($componentController, $rootScope) => {
$scope = $rootScope.$new();
$element = angular.element('<div><div></div></div>');
controller = $componentController('vnSpinner', {$scope, $element});
beforeEach(angular.mock.inject(($compile, $rootScope) => {
$element = $compile(`<vn-spinner></vn-spinner>`)($rootScope);
controller = $element.controller('vnSpinner');
}));
afterEach(() => {
$element.remove();
});
describe('enable()', () => {
it(`should call start() based on a boolean value passed as argument`, () => {
it(`should call start() when enable is set to true`, () => {
spyOn(controller, 'start');
spyOn(controller, 'stop');
controller.enable = true;
expect(controller.start).toHaveBeenCalledWith();
expect(controller.stop).not.toHaveBeenCalledWith();
});
it(`should call stop() based on a boolean value passed as argument`, () => {
spyOn(controller, 'start');
it(`should call stop() when enable is set to false`, () => {
spyOn(controller, 'stop');
controller.enable = false;
expect(controller.start).not.toHaveBeenCalledWith();
expect(controller.stop).toHaveBeenCalledWith();
});
});
describe('start()', () => {
it(`should call start() on the controller.materialSpinner then set controllers._enable to be truthy`, () => {
controller.spinner = {MaterialSpinner: {start: () => {}}};
spyOn(controller.spinner.MaterialSpinner, 'start');
controller._enable = false;
it(`should set enable to true`, () => {
controller.start();
expect(controller.spinner.MaterialSpinner.start).toHaveBeenCalledWith();
expect(controller._enable).toBeTruthy();
expect(controller.enable).toBeTruthy();
});
});
describe('stop()', () => {
it(`should call stop() on the controller.materialSpinner then set controllers._enable to be truthy`, () => {
controller.spinner = {MaterialSpinner: {stop: () => {}}};
spyOn(controller.spinner.MaterialSpinner, 'stop');
controller._enable = true;
it(`should set enable to false`, () => {
controller.stop();
expect(controller.spinner.MaterialSpinner.stop).toHaveBeenCalledWith();
expect(controller._enable).toBeFalsy();
expect(controller.enable).toBeFalsy();
});
});
});

View File

@ -1,3 +0,0 @@
vn-spinner {
display: inline-block;
}

View File

@ -0,0 +1,60 @@
@import "variables";
vn-spinner {
display: inline-block;
min-height: 28px;
min-width: 28px;
& > .loader {
position: relative;
margin: 0 auto;
width: 100%;
height: 100%;
&:before {
content: '';
display: block;
padding-top: 100%;
}
& > .circular {
animation: rotate 2s linear infinite;
transform-origin: center center;
height: 100%;
width: 100%;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
margin: auto;
& > .path {
stroke: $color-main;
stroke-dasharray: 1, 200;
stroke-dashoffset: 0;
stroke-linecap: square;
stroke-width: 6px;
animation: dash 1.5s ease-in-out infinite;
}
}
}
@keyframes rotate {
100% {
transform: rotate(360deg);
}
}
@keyframes dash {
0% {
stroke-dasharray: 1, 200;
stroke-dashoffset: 0;
}
50% {
stroke-dasharray: 89, 200;
stroke-dashoffset: -35px;
}
100% {
stroke-dasharray: 89, 200;
stroke-dashoffset: -124px;
}
}
}

View File

@ -41,11 +41,5 @@ vn-step-control {
& > .buttons > .step {
display: flex
}
& > .buttons > .step > .mdl-button {
line-height: 32px;
font-size: 12px;
padding: 0 12px;
height: 32px
}
}
}

View File

@ -0,0 +1,13 @@
import ngModule from '../../module';
import Button from '../button';
export default class Controller extends Button {
constructor($element, $scope) {
super($element, $scope);
this.type = 'submit';
}
}
ngModule.vnComponent('vnSubmit', {
controller: Controller
});

View File

@ -1,6 +0,0 @@
<input
class="mdl-button mdl-js-button mdl-button--raised mdl-button--colored"
type="submit"
translate-attr="{value: $ctrl.label}"
value="$ctrl.label">
</input>

View File

@ -1,25 +0,0 @@
import ngModule from '../../module';
import Input from '../../lib/input';
export default class Controller extends Input {
constructor($element, $scope) {
super($element, $scope);
this.$element = $element;
this.input = $element[0].querySelector('input');
}
set disabled(value) {
this.input.disabled = value;
}
}
Controller.$inject = ['$element', '$scope'];
ngModule.component('vnSubmit', {
template: require('./submit.html'),
controller: Controller,
bindings: {
label: '@?',
disabled: '<?',
}
});

View File

@ -1,6 +1,6 @@
import ngModule from '../../module';
import Component from '../../lib/component';
import Input from '../../lib/input';
import FormInput from '../form-input';
import './style.scss';
export default class Controller extends Component {
@ -37,7 +37,7 @@ export default class Controller extends Component {
}
let inputCtrl = this.field[0].firstElementChild.$ctrl;
if (inputCtrl instanceof Input) {
if (inputCtrl instanceof FormInput) {
let evt = new MouseEvent('click', {
bubbles: true,
cancelable: true,

View File

@ -19,15 +19,24 @@ export default class Toggle extends FormInput {
}
set disabled(value) {
this.element.tabIndex = !value ? 0 : -1;
this.element.classList.toggle('disabled', Boolean(value));
this._disabled = value;
this.classList.toggle('disabled', Boolean(value));
this.refreshTabIndex();
}
get disabled() {
return this._disabled;
}
set readonly(value) {
this._readonly = value;
this.classList.toggle('readonly', Boolean(value));
}
get readonly() {
return this._readonly;
}
onKeydown(event) {
if (event.code == 'Space')
this.onClick(event);

View File

@ -11,7 +11,10 @@
cursor: inherit;
}
& > span {
font-size: $input-font-size;
font-size: $font-size;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
& > .btn {
position: relative;

View File

@ -13,7 +13,7 @@ export default class Tooltip extends Component {
constructor($element, $scope, $timeout) {
super($element, $scope);
this.$timeout = $timeout;
$element.addClass('vn-tooltip mdl-shadow--4dp');
$element.addClass('vn-tooltip vn-shadow');
this.position = 'down';
this.margin = 10;
}

View File

@ -0,0 +1,20 @@
<div class="node clickable">
<vn-icon
class="arrow"
ng-class="{invisible: !$ctrl.item.sons}"
icon="keyboard_arrow_down"
translate-attr="::{title: 'Toggle'}">
</vn-icon>
<section class="content"></section>
<section class="buttons" ng-if="::!$ctrl.treeview.readOnly">
<vn-icon-button translate-attr="::{title: 'Remove'}"
icon="delete"
ng-click="$ctrl.treeview.onRemove($ctrl.item)"
ng-if="$ctrl.item.parent">
</vn-icon-button>
<vn-icon-button translate-attr="::{title: 'Create'}"
icon="add_circle"
ng-click="$ctrl.treeview.onCreate($ctrl.item)">
</vn-icon-button>
</section>
</div>

View File

@ -2,22 +2,33 @@ import ngModule from '../../module';
class Controller {
constructor($element, $scope, $compile) {
this.$element = $element;
this.$scope = $scope;
this.$compile = $compile;
this.element = $element[0];
this.element.$ctrl = this;
this.element.droppable = true;
this.dropCount = 0;
this.element.classList.add('vn-droppable');
}
$onInit() {
const transcludeElement = this.element.querySelector('.content');
const content = angular.element(transcludeElement);
if (this.item.parent) {
this.treeview.$transclude(($clone, $scope) => {
this.$contentScope = $scope;
$scope.item = this.item;
this.$element.append($clone);
content.append($clone);
});
this.element.draggable = true;
this.element.classList.add('vn-draggable');
} else {
let template = `<span translate>{{$ctrl.treeview.rootLabel}}</span>`;
let $clone = this.$compile(template)(this.$scope);
this.$element.append($clone);
content.append($clone);
}
}
@ -25,10 +36,21 @@ class Controller {
if (this.$contentScope)
this.$contentScope.$destroy();
}
dragEnter() {
this.dropCount++;
if (element != this.dropping) {
this.undrop();
if (element) element.classList.add('dropping');
this.dropping = element;
}
}
}
Controller.$inject = ['$element', '$scope', '$compile'];
ngModule.component('vnTreeviewContent', {
ngModule.component('vnTreeviewChild', {
template: require('./child.html'),
controller: Controller,
bindings: {
item: '<'

Some files were not shown because too many files have changed in this diff Show More