diff --git a/front/core/components/check/check.html b/front/core/components/check/check.html deleted file mode 100644 index 57d2e407f..000000000 --- a/front/core/components/check/check.html +++ /dev/null @@ -1,12 +0,0 @@ -
-
-
-
- - {{::$ctrl.label}} - - - info_outline - \ No newline at end of file diff --git a/front/core/components/check/index.html b/front/core/components/check/index.html new file mode 100644 index 000000000..dd0a5d012 --- /dev/null +++ b/front/core/components/check/index.html @@ -0,0 +1,12 @@ +
+
+
+
+ + {{::$ctrl.label}} + + + \ No newline at end of file diff --git a/front/core/components/check/check.js b/front/core/components/check/index.js similarity index 56% rename from front/core/components/check/check.js rename to front/core/components/check/index.js index 24f98993b..471be638a 100644 --- a/front/core/components/check/check.js +++ b/front/core/components/check/index.js @@ -2,25 +2,32 @@ import ngModule from '../../module'; import Component from '../../lib/component'; import './style.scss'; +/** + * Basic element for user input. You can use this to supply a way for the user + * to toggle an option. + * + * @property {String} label Label to display along the component + * @property {any} field The value with which the element is linked + * @property {Boolean} checked Whether the checkbox is checked + * @property {Boolean} disabled Put component in disabled mode + * @property {Boolean} tripleState Switch between three states when clicked + * @property {Boolean} indeterminate Sets the element into indeterminate state + * @property {String} info Shows a text information tooltip to the user + */ export default class Controller extends Component { constructor($element, $, $attrs) { super($element, $); - this.hasInfo = Boolean($attrs.info); - this.info = $attrs.info || null; let element = this.element; element.addEventListener('click', e => this.onClick(e)); - element.addEventListener('keydown', e => this.onClick(e)); + element.addEventListener('keydown', e => this.onKeydown(e)); element.tabIndex = 0; - - this.check = element.querySelector('.check'); } set field(value) { this._field = value; - let isIndeterminate = Boolean(value == null && this.tripleState); - this.check.classList.toggle('checked', Boolean(value)); - this.check.classList.toggle('indeterminate', isIndeterminate); + this.element.classList.toggle('checked', Boolean(value)); + this.indeterminate = Boolean(value == null && this.tripleState); } get field() { @@ -29,7 +36,7 @@ export default class Controller extends Component { set disabled(value) { this.element.tabIndex = !value ? 0 : -1; - this.check.classList.toggle('disabled', Boolean(value)); + this.element.classList.toggle('disabled', Boolean(value)); this._disabled = value; } @@ -37,6 +44,15 @@ export default class Controller extends Component { return this._disabled; } + set indeterminate(value) { + this._indeterminate = value; + this.element.classList.toggle('indeterminate', Boolean(value)); + } + + get indeterminate() { + return this._indeterminate; + } + set tripleState(value) { this._tripleState = value; this.field = this.field; @@ -53,9 +69,9 @@ export default class Controller extends Component { if (this.tripleState) { if (this.field == null) - this.field = false; - else if (!this.field) this.field = true; + else if (this.field) + this.field = false; else this.field = null; } else @@ -63,6 +79,7 @@ export default class Controller extends Component { this.$.$applyAsync(); this.element.dispatchEvent(new Event('change')); + this.emit('change', {value: this.field}); } onKeydown(event) { @@ -74,15 +91,16 @@ export default class Controller extends Component { Controller.$inject = ['$element', '$scope', '$attrs']; ngModule.component('vnCheck', { - template: require('./check.html'), + template: require('./index.html'), controller: Controller, bindings: { - field: '=?', label: '@?', - disabled: ' { expect($ctrl.field).toEqual(false); }); - it(`should check value and change to null when clicked`, () => { + it(`should check value and change to false when clicked`, () => { $ctrl.field = true; $ctrl.tripleState = true; element.click(); - expect($ctrl.field).toEqual(null); + expect($ctrl.field).toEqual(false); }); - it(`should set value to null and change to false when clicked`, () => { + it(`should set value to null and change to true when clicked`, () => { $ctrl.field = null; $ctrl.tripleState = true; element.click(); - expect($ctrl.field).toEqual(false); + expect($ctrl.field).toEqual(true); }); it(`should cast value to boolean when clicked`, () => { diff --git a/front/core/components/check/style.scss b/front/core/components/check/style.scss index c79ec66a9..0d1669a68 100644 --- a/front/core/components/check/style.scss +++ b/front/core/components/check/style.scss @@ -2,10 +2,13 @@ vn-check { position: relative; - cursor: pointer; display: inline-block; outline: none; + cursor: pointer; + &.disabled { + cursor: initial; + } & > .check { position: relative; box-sizing: border-box; @@ -16,7 +19,7 @@ vn-check { height: 20px; transition: background 250ms; border: 2px solid #666; - margin: 3px; + margin: 6px 0; margin-right: .4em; & > .mark { @@ -25,15 +28,15 @@ vn-check { display: block; border-width: 0; } - &.checked { - background-color: $color-main; - border-color: $color-main; + } + &.checked > .check { + background-color: $color-main; + border-color: $color-main; - & > .focus { - background-color: rgba($color-main, .15); - } + & > .focus-mark { + background-color: rgba($color-main, .15); } - &.checked > .mark { + & > .mark { top: 0; left: 4px; transform: rotate(45deg); @@ -43,16 +46,16 @@ vn-check { border-top: 0; border-left: 0; } - &.indeterminate > .mark { - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - width: 12px; - height: 2px; - border-bottom: 2px solid #666; - } } - & > .check > .focus { + &.indeterminate > .check > .mark { + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: 12px; + height: 2px; + border-bottom: 2px solid #666; + } + & > .check > .focus-mark { position: absolute; top: 50%; left: 50%; @@ -66,13 +69,12 @@ vn-check { transition: transform 250ms; background-color: rgba(0, 0, 0, .1); } - &:focus > .check:not(.disabled) > .focus { + &:focus:not(.disabled) > .check > .focus-mark { transform: scale3d(1, 1, 1); } - & > i { - padding-left: 5px; - position: absolute; + & > vn-icon { + margin-left: 5px; color: $color-font-secondary; - font-size: 20px; + vertical-align: middle; } } diff --git a/front/core/components/index.js b/front/core/components/index.js index 24abdb661..e8adb008e 100644 --- a/front/core/components/index.js +++ b/front/core/components/index.js @@ -19,8 +19,6 @@ import './menu/menu'; import './multi-check/multi-check'; import './date-picker/date-picker'; import './button/button'; -import './check/check'; -import './radio-group/radio-group'; import './textarea/textarea'; import './icon-button/icon-button'; import './submit/submit'; @@ -31,16 +29,18 @@ import './label-value/label-value'; import './paging/paging'; import './pagination/pagination'; import './searchbar/searchbar'; +import './scroll-up/scroll-up'; import './table'; import './td-editable'; -import './th'; import './input-range'; +import './calendar'; +import './check'; import './chip'; import './color-legend'; import './input-number'; import './input-time'; import './input-file'; +import './radio'; +import './th'; import './treeview'; import './treeview/child'; -import './calendar'; -import './scroll-up/scroll-up'; diff --git a/front/core/components/input-number/index.html b/front/core/components/input-number/index.html index 9fd024280..19b5c58e6 100644 --- a/front/core/components/input-number/index.html +++ b/front/core/components/input-number/index.html @@ -2,13 +2,6 @@ ng-class="{selected: $ctrl.hasFocus}">
- -
+ + { - if (!isNaN(this.value)) - this.input.value = this.value; - this.validateValue(); - this.emit('change', {event}); }); - - this.input.addEventListener('focus', event => { - this.emit('focus', {event}); - }); } /** @@ -49,12 +41,7 @@ export default class InputNumber extends Input { this.input.value = value; this._value = value; - - if (this.hasValue) - this.element.classList.add('not-empty'); - else - this.element.classList.remove('not-empty'); - + this.element.classList.toggle('not-empty', this.hasValue); this.validateValue(); } @@ -111,6 +98,7 @@ export default class InputNumber extends Input { */ stepUp() { this.input.stepUp(); + this.input.dispatchEvent(new Event('change')); } /** @@ -118,6 +106,7 @@ export default class InputNumber extends Input { */ stepDown() { this.input.stepDown(); + this.input.dispatchEvent(new Event('change')); } } InputNumber.$inject = ['$element', '$scope', '$attrs', 'vnTemplate']; diff --git a/front/core/components/input-number/style.scss b/front/core/components/input-number/style.scss index 1f7bdff57..e25299db2 100644 --- a/front/core/components/input-number/style.scss +++ b/front/core/components/input-number/style.scss @@ -3,18 +3,13 @@ vn-input-number { @extend vn-textfield; - input { - text-align: center !important; - } + vn-icon[icon=add], - vn-icon[icon=remove]{ + vn-icon[icon=remove] { &:not(:hover){ color: $color-font-secondary; } i { - -moz-user-select: none; - -webkit-user-select: none; - -ms-user-select: none; user-select: none; } } diff --git a/front/core/components/input-time/index.js b/front/core/components/input-time/index.js index 41f76c086..c85bb37cf 100644 --- a/front/core/components/input-time/index.js +++ b/front/core/components/input-time/index.js @@ -35,7 +35,7 @@ export default class InputTime extends Input { */ set value(value) { this.updateValue(value); - this.input.value = this.$filter('date')(value, 'HH:mm'); + this.input.value = this.$filter('dateTime')(value, 'HH:mm'); } updateValue(value) { diff --git a/front/core/components/multi-check/multi-check.html b/front/core/components/multi-check/multi-check.html index 2d51324f0..c09fd246c 100644 --- a/front/core/components/multi-check/multi-check.html +++ b/front/core/components/multi-check/multi-check.html @@ -1,5 +1,5 @@ - + translate-attr="{title: 'Check all'}"> \ No newline at end of file diff --git a/front/core/components/multi-check/style.scss b/front/core/components/multi-check/style.scss index 405c28414..b1e3d9432 100644 --- a/front/core/components/multi-check/style.scss +++ b/front/core/components/multi-check/style.scss @@ -1,5 +1,5 @@ vn-multi-check { - md-checkbox { + vn-check { margin-bottom: 0.8em } } \ No newline at end of file diff --git a/front/core/components/radio-group/radio-group.html b/front/core/components/radio-group/radio-group.html deleted file mode 100644 index 3b389d2be..000000000 --- a/front/core/components/radio-group/radio-group.html +++ /dev/null @@ -1,8 +0,0 @@ - - - {{::option.label}} - - \ No newline at end of file diff --git a/front/core/components/radio-group/radio-group.js b/front/core/components/radio-group/radio-group.js deleted file mode 100644 index 80c77a7e2..000000000 --- a/front/core/components/radio-group/radio-group.js +++ /dev/null @@ -1,41 +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.hasInfo = Boolean($attrs.info); - this.info = $attrs.info || null; - } - - get model() { - return this._model; - } - - set model(value) { - this._model = value; - } - - get field() { - return this._model; - } - - set field(value) { - this._model = value; - } -} - -Controller.$inject = ['$element', '$scope', '$attrs']; - -ngModule.component('vnRadioGroup', { - template: require('./radio-group.html'), - controller: Controller, - - bindings: { - field: '=?', - options: ' +
+
+
+ + {{::$ctrl.label}} + \ No newline at end of file diff --git a/front/core/components/radio/index.js b/front/core/components/radio/index.js new file mode 100644 index 000000000..a8475c256 --- /dev/null +++ b/front/core/components/radio/index.js @@ -0,0 +1,93 @@ +import ngModule from '../../module'; +import Component from '../../lib/component'; +import './style.scss'; + +/** + * Basic element for user input. You can use this to supply a way for the user + * to pick an option from multiple choices. + * + * @property {String} label Label to display along the component + * @property {any} field The value with which the element is linked + * @property {Boolean} checked Whether the radio is checked + * @property {String} val The actual value of the option + * @property {Boolean} disabled Put component in disabled mode + */ +export default class Controller extends Component { + constructor($element, $, $attrs) { + super($element, $); + this.hasInfo = Boolean($attrs.info); + this.info = $attrs.info || null; + + let element = this.element; + element.addEventListener('click', e => this.onClick(e)); + element.addEventListener('keydown', e => this.onKeydown(e)); + element.tabIndex = 0; + } + + set field(value) { + this._field = value; + this.element.classList.toggle('checked', + Boolean(value) && value == this.val); + } + + get field() { + return this._field; + } + + set val(value) { + this._val = value; + this.field = this.field; + } + + get val() { + return this._val; + } + + set checked(value) { + this.field = value ? this.val : null; + this.$.$applyAsync(); + } + + get checked() { + return this.field == this.val; + } + + set disabled(value) { + this.element.tabIndex = !value ? 0 : -1; + this.element.classList.toggle('disabled', Boolean(value)); + this._disabled = value; + } + + get disabled() { + return this._disabled; + } + + onClick(event) { + if (this.disabled) return; + event.preventDefault(); + + this.field = this.val; + this.$.$applyAsync(); + this.element.dispatchEvent(new Event('change')); + } + + onKeydown(event) { + if (event.code == 'Space') + this.onClick(event); + } +} + +Controller.$inject = ['$element', '$scope', '$attrs']; + +ngModule.component('vnRadio', { + template: require('./index.html'), + controller: Controller, + + bindings: { + label: '@?', + field: '=?', + checked: ' { + let $element; + let $ctrl; + let element; + + beforeEach(angular.mock.module('vnCore', $translateProvider => { + $translateProvider.translations('en', {}); + })); + + beforeEach(inject(($compile, $rootScope) => { + $element = $compile(` { + $element.remove(); + }); + + describe('field() setter', () => { + it(`should set model value`, () => { + $ctrl.field = true; + + expect($ctrl.field).toEqual(true); + }); + + it(`should uncheck value and change to true when clicked`, () => { + $ctrl.field = false; + element.click(); + + expect($ctrl.field).toEqual(true); + }); + + it(`should check value and change to false when clicked`, () => { + $ctrl.field = true; + element.click(); + + expect($ctrl.field).toEqual(false); + }); + + it(`should uncheck value and change to null when clicked`, () => { + $ctrl.field = false; + $ctrl.tripleState = true; + element.click(); + + expect($ctrl.field).toEqual(null); + }); + + it(`should set value to null and change to true when clicked`, () => { + $ctrl.field = null; + $ctrl.tripleState = true; + element.click(); + + expect($ctrl.field).toEqual(true); + }); + + it(`should cast value to boolean when clicked`, () => { + $ctrl.field = 0; + element.click(); + + expect($ctrl.field).toEqual(true); + }); + }); +}); diff --git a/front/core/components/radio/style.scss b/front/core/components/radio/style.scss new file mode 100644 index 000000000..de49286b4 --- /dev/null +++ b/front/core/components/radio/style.scss @@ -0,0 +1,62 @@ +@import "variables"; + +vn-radio { + position: relative; + cursor: pointer; + display: inline-block; + outline: none; + + &.disabled { + cursor: initial; + } + & > .radio { + position: relative; + box-sizing: border-box; + display: inline-block; + vertical-align: middle; + border-radius: 50%; + width: 20px; + height: 20px; + border: 2px solid #666; + margin: 6px 0; + margin-right: .4em; + + & > .mark { + transition: background 250ms; + } + } + &.checked > .radio { + border-color: $color-main; + + & > .mark { + position: absolute; + border-radius: 50%; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: 10px; + height: 10px; + background-color: $color-main; + } + & > .focus-mark { + background-color: rgba($color-main, .15); + } + } + & > .radio > .focus-mark { + position: absolute; + top: 50%; + left: 50%; + height: 38px; + width: 38px; + margin-top: -19px; + margin-left: -19px; + border-radius: 50%; + transform: scale3d(0, 0, 0); + transition: background 250ms; + transition: transform 250ms; + background-color: rgba(0, 0, 0, .1); + } + &:focus:not(.disabled) > .radio > .focus-mark { + transform: scale3d(1, 1, 1); + } +} diff --git a/front/core/components/table/style.scss b/front/core/components/table/style.scss index a23fa4d53..29b163950 100644 --- a/front/core/components/table/style.scss +++ b/front/core/components/table/style.scss @@ -184,7 +184,7 @@ vn-table { float: right; margin: 0!important; } - md-checkbox { + vn-check { margin: 0; } } \ No newline at end of file diff --git a/front/core/components/treeview/child.html b/front/core/components/treeview/child.html index eedd63b19..bb0bcb569 100644 --- a/front/core/components/treeview/child.html +++ b/front/core/components/treeview/child.html @@ -1,55 +1,61 @@ \ No newline at end of file +
  • +
    + + + + + + +
    + + +
  • +
  • +
    + + +
    + Create new one +
    +
    +
  • + \ No newline at end of file diff --git a/front/core/components/treeview/child.js b/front/core/components/treeview/child.js index 8fecbd89b..4441963f0 100644 --- a/front/core/components/treeview/child.js +++ b/front/core/components/treeview/child.js @@ -7,7 +7,9 @@ class Controller extends Component { this.$scope = $scope; } - toggle(item) { + toggle(event, item) { + if (event.defaultPrevented || !item.sons) return; + event.preventDefault(); this.treeview.onToggle(item); } diff --git a/front/core/components/treeview/index.html b/front/core/components/treeview/index.html index 36e2591f9..a200c913a 100644 --- a/front/core/components/treeview/index.html +++ b/front/core/components/treeview/index.html @@ -1,4 +1,5 @@ - div > .arrow { min-width: 24px; - margin-right: 10px + margin-right: 10px; + transition: transform 200ms; } - - .description { - pointer-events: none; - padding-left: 5px + &.expanded > div > .arrow { + transform: rotate(180deg); } - } - - li vn-icon { - cursor: pointer; - } - - li ul { - padding-left: 1.8em; - } - - li > vn-horizontal { - padding: 5px - } - - li > vn-horizontal:hover { - background-color: $color-hover-cd - } - - li.expanded > vn-horizontal > .actions > vn-icon[icon="keyboard_arrow_down"] { - transition: all 0.2s; - transform: rotate(180deg); - } - - li.collapsed > vn-horizontal > .actions > vn-icon[icon="keyboard_arrow_down"] { - transition: all 0.2s; - transform: rotate(0deg); - } - - li.included { - & > vn-horizontal > .description { - color: $color-notice; - font-weight: bold; + & > .node { + @extend %clickable; + display: flex; + padding: 5px; + align-items: center; + + & > vn-check:not(.indeterminate) { + color: $color-main; + + & > .check { + border-color: $color-main; + } + } + & > vn-check.checked { + color: $color-main; + } } - - & > vn-horizontal > vn-check .md-icon { - background-color: $color-notice - } - } - - li.excluded { - & > vn-horizontal > .description { - color: $color-alert; - font-weight: bold; - } - - & > vn-horizontal > vn-check .md-icon { - background-color: $color-alert; - border-color: transparent + ul { + padding-left: 2.2em; } } } - vn-icon-button { padding: 0 } diff --git a/modules/agency/front/events/index.html b/modules/agency/front/events/index.html index a09038087..fa114b9bc 100644 --- a/modules/agency/front/events/index.html +++ b/modules/agency/front/events/index.html @@ -80,10 +80,23 @@ on-response="$ctrl.onSave(response)"> - - + + + + + + + +
    diff --git a/modules/agency/front/events/index.js b/modules/agency/front/events/index.js index 614641cbb..1f741962b 100644 --- a/modules/agency/front/events/index.js +++ b/modules/agency/front/events/index.js @@ -41,19 +41,6 @@ class Controller { wday.abr = locale.substr(0, 1); } - this.options = [ - { - label: 'One day', - value: 'day' - }, { - label: 'Range of dates', - value: 'range' - }, { - label: 'Indefinitely', - value: 'indefinitely' - } - ]; - this.$http.get(`/api/Zones/${$stateParams.id}/exclusions`) .then(res => this.$.exclusions = res.data);