From 78a0bf56b53b94d0ef0ccd5dc7bc3fe998f2633b Mon Sep 17 00:00:00 2001 From: Axel Peter Date: Wed, 28 Nov 2018 17:05:36 +0100 Subject: [PATCH 1/2] refactor(oui-select): use ui-select in a proper way --- package.json | 3 +- packages/oui-field/src/index.spec.js | 10 +- packages/oui-select-picker/src/index.spec.js | 36 +- packages/oui-select/README.md | 110 +- packages/oui-select/src/index.js | 14 +- packages/oui-select/src/index.spec.js | 106 +- packages/oui-select/src/select.controller.js | 34 +- packages/oui-select/src/select.directive.js | 16 +- packages/oui-select/src/select.html | 24 +- .../oui-select/src/templates/choices.html | 21 +- packages/oui-select/src/templates/footer.html | 1 + packages/oui-select/src/templates/header.html | 1 + .../src/templates/match-multiple.html | 16 + packages/oui-select/src/templates/match.html | 32 +- .../oui-select/src/templates/no-choice.html | 4 + .../src/templates/select-multiple.html | 24 + packages/oui-select/src/templates/select.html | 27 +- packages/oui-select/src/ui-select.js | 2479 ----------------- yarn.lock | 5 + 19 files changed, 306 insertions(+), 2657 deletions(-) create mode 100644 packages/oui-select/src/templates/footer.html create mode 100644 packages/oui-select/src/templates/header.html create mode 100644 packages/oui-select/src/templates/match-multiple.html create mode 100644 packages/oui-select/src/templates/no-choice.html create mode 100644 packages/oui-select/src/templates/select-multiple.html delete mode 100644 packages/oui-select/src/ui-select.js diff --git a/package.json b/package.json index a2c6eff0..774b0144 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,8 @@ "clipboard": "^2.0.1", "escape-string-regexp": "^1.0.5", "flatpickr": "^4.5.2", - "popper.js": "^1.14.4" + "popper.js": "^1.14.4", + "ui-select": "^0.19.8" }, "peerDependencies": { "angular": ">=1.6.x", diff --git a/packages/oui-field/src/index.spec.js b/packages/oui-field/src/index.spec.js index ee391b5e..ab45f2e3 100644 --- a/packages/oui-field/src/index.spec.js +++ b/packages/oui-field/src/index.spec.js @@ -483,7 +483,7 @@ describe("ouiField", () => { }); describe("with oui-select", () => { - const getDropdownButton = element => element[0].querySelector(".oui-button_dropdown"); + const getDropdownButton = element => element[0].querySelector(".ui-select-match"); const getSelectController = element => element.find("oui-select").controller("ouiSelect"); it("should give focus to oui-select after on label click", () => { @@ -506,14 +506,14 @@ describe("ouiField", () => { ] }); + $timeout.flush(); + const selectController = getSelectController(element); const $label = angular.element(getLabel(element)); - - $timeout.flush(); - selectController.uiSelectDropdownTrigger.focus = jasmine.createSpy(); + selectController.$select.focusser[0].focus = jasmine.createSpy(); $label.triggerHandler("click"); - expect(selectController.uiSelectDropdownTrigger.focus).toHaveBeenCalled(); + expect(selectController.$select.focusser[0].focus).toHaveBeenCalled(); }); it("should show errors when blur is triggered on select", () => { diff --git a/packages/oui-select-picker/src/index.spec.js b/packages/oui-select-picker/src/index.spec.js index 6f1b018f..2a9fe0df 100644 --- a/packages/oui-select-picker/src/index.spec.js +++ b/packages/oui-select-picker/src/index.spec.js @@ -102,10 +102,10 @@ describe("ouiSelectPicker", () => { it("should allow to pick one of values attribute", () => { const element = TestUtils.compileTemplate(''); - const selectElement = element[0].querySelector("oui-select"); - expect(angular.element(selectElement)).not.toBeUndefined(); + const selectElement = angular.element(element[0].querySelector(".ui-select-match")); + selectElement.triggerHandler("click"); - const selectValues = element[0].querySelectorAll(".oui-dropdown-option"); + const selectValues = element[0].querySelectorAll(".ui-select-choices-row"); expect(angular.element(selectValues[0]).text().trim()).toEqual("aValue"); }); @@ -119,7 +119,10 @@ describe("ouiSelectPicker", () => { it("should display select values according to match", () => { const element = TestUtils.compileTemplate(''); - const selectValues = element[0].querySelectorAll(".oui-dropdown-option"); + const selectElement = angular.element(element[0].querySelector(".ui-select-match")); + selectElement.triggerHandler("click"); + + const selectValues = element[0].querySelectorAll(".ui-select-choices-row"); expect(angular.element(selectValues[1]).text().trim()).toEqual("bValue"); }); }); @@ -239,28 +242,33 @@ describe("ouiSelectPicker", () => { onChange: onChangeSpy }); - const selectPickerComponent1 = element.children()[0]; - const selectPickerComponent2 = element.children()[1]; - const $radioElement1 = angular.element(selectPickerComponent1).find("input"); - const $radioElement2 = angular.element(selectPickerComponent2).find("input"); - const $triggerElement1 = angular.element(selectPickerComponent1.querySelector("button.oui-dropdown__trigger")); - const $triggerElement2 = angular.element(selectPickerComponent2.querySelector("button.oui-dropdown__trigger")); + const selectPickers = element.find("oui-select-picker"); + + const selectPickerComponent1 = selectPickers[0]; + const $radioElement1 = angular.element(selectPickerComponent1.querySelector(".oui-select-picker__input")); + const $triggerElement1 = angular.element(selectPickerComponent1.querySelector(".ui-select-match")); + + const selectPickerComponent2 = selectPickers[1]; + const $radioElement2 = angular.element(selectPickerComponent2.querySelector(".oui-select-picker__input")); + const $triggerElement2 = angular.element(selectPickerComponent2.querySelector(".ui-select-match")); $radioElement1.prop("checked", true); $triggerElement1.triggerHandler("click"); - expect(angular.element(selectPickerComponent1.querySelector(".oui-ui-select-container")).hasClass("oui-ui-select-container_open")).toBe(true); - const $choiceElement1 = angular.element(selectPickerComponent1.querySelector(".ui-select-choices li button")); + + const $choiceElement1 = angular.element(selectPickerComponent1.querySelector(".ui-select-choices-row")); $choiceElement1.triggerHandler("click"); - expect(angular.element(selectPickerComponent1.querySelector(".oui-ui-select-container")).hasClass("oui-ui-select-container_open")).toBe(false); $timeout.flush(); + expect(onChangeSpy).toHaveBeenCalledWith("aValue"); $radioElement1.prop("checked", false); $radioElement2.prop("checked", true); $triggerElement2.triggerHandler("click"); - const $choicesElement2 = angular.element(selectPickerComponent2.querySelector(".ui-select-choices li button")); + + const $choicesElement2 = angular.element(selectPickerComponent2.querySelector(".ui-select-choices-row")); $choicesElement2.triggerHandler("click"); $timeout.flush(); + expect(onChangeSpy).toHaveBeenCalledWith("cValue"); }); }); diff --git a/packages/oui-select/README.md b/packages/oui-select/README.md index d6b4e6a7..766721fa 100644 --- a/packages/oui-select/README.md +++ b/packages/oui-select/README.md @@ -4,51 +4,44 @@ ## Usage +### Basic (String array) + +```html:preview + + +``` + ### Basic (Object array) ```html:preview - + match="name"> ``` -### Basic (String array) +### Placeholder ```html:preview - + items="['a', 'b', 'c']"> ``` -### Grouping / Custom template +### Searchable ```html:preview -
- - Code: - + searchable>
``` @@ -56,44 +49,76 @@ ```html:preview - ``` ### Disabled Items + + For each $item in items array, disable-item will be called with current $item as an argument.
+ If it returns true, $item will be disabled. +
+ ```html:preview - + match="name"> ``` -**Note**: For each `$item` in `items` array, `disable-item` will be called with current `$item` as an argument. If it returns true, `$item` will be disabled. +### Grouping + +```html:preview + + +``` + +### Custom option template + + + Template inside oui-select component will be used as the content of each option.
+ You can use $item variable to get option value for your template. +
+ +```html:preview + +
+ + Code: + +
+``` ### On Change -**Note**: Model will not be refreshed until the `on-change` callback hasn't returned. If you want to access the new model inside the `on-change` callback you need to use the `modelValue` variable as below. + + Model will not be refreshed until the on-change callback hasn't returned.
+ If you want to access the new model inside the on-change callback you need to use the modelValue variable as below. +
```html:preview -
+ on-focus="$ctrl.onFocus()"> +
Code: @@ -123,8 +147,7 @@ | ---- | ---- | ---- | ---- | ---- | ---- | ---- | `model` | object | = | no | n/a | n/a | model bound to component | `name` | string | @? | yes | n/a | n/a | name of the form component -| `data-align` | string | @? | yes | `start`, `end` | `start` | dropdown alignment -| `data-title` | string | @? | yes | n/a | n/a | title attribute of the component +| `title` | string | @? | yes | n/a | n/a | title attribute of the component | `placeholder` | string | @? | yes | n/a | n/a | placeholder displayed when model is undefined | `match` | string | @? | no | n/a | n/a | property of item to show as selected item | `items` | array | < | no | n/a | n/a | array used to populate the list @@ -136,3 +159,6 @@ | `on-focus` | function | & | no | n/a | n/a | called on focus | `on-change` | function | & | no | n/a | n/a | handler triggered when value has changed +#### Deprecated + +* `data-align`: Unused diff --git a/packages/oui-select/src/index.js b/packages/oui-select/src/index.js index 852aa0c3..baf7f18e 100644 --- a/packages/oui-select/src/index.js +++ b/packages/oui-select/src/index.js @@ -1,11 +1,21 @@ -import "./ui-select"; +import "ui-select"; import Select from "./select.directive"; export default angular .module("oui.select", [ "oui.field", - "oui.ui-select", + "ui.select", "ngSanitize" ]) + .run(["$templateCache", ($templateCache) => { + $templateCache.put("oui-ui-select/choices.tpl.html", require("./templates/choices.html")); + $templateCache.put("oui-ui-select/footer.tpl.html", require("./templates/footer.html")); + $templateCache.put("oui-ui-select/header.tpl.html", require("./templates/header.html")); + $templateCache.put("oui-ui-select/match.tpl.html", require("./templates/match.html")); + $templateCache.put("oui-ui-select/match-multiple.tpl.html", require("./templates/match-multiple.html")); + $templateCache.put("oui-ui-select/no-choice.tpl.html", require("./templates/no-choice.html")); + $templateCache.put("oui-ui-select/select.tpl.html", require("./templates/select.html")); + $templateCache.put("oui-ui-select/select-multiple.tpl.html", require("./templates/select-multiple.html")); + }]) .directive("ouiSelect", Select) .name; diff --git a/packages/oui-select/src/index.spec.js b/packages/oui-select/src/index.spec.js index 8acbe5cf..f07492ed 100644 --- a/packages/oui-select/src/index.spec.js +++ b/packages/oui-select/src/index.spec.js @@ -15,12 +15,12 @@ describe("ouiSelect", () => { $timeout = _$timeout_; })); - const openClass = "oui-ui-select-container_open"; - const selectedItemClass = "selected"; + const selectedItemClass = "ui-select-choices-row_selected"; - const getContainer = element => element[0].querySelector(".oui-ui-select-container"); - const getDropdownButton = element => element[0].querySelector(".oui-button_dropdown"); + const getContainer = element => element[0].querySelector(".ui-select-container"); + const getDropdownButton = element => element[0].querySelector(".ui-select-match"); const getDropdown = element => element[0].querySelector(".ui-select-choices-content"); + const getFocusser = element => element[0].querySelector(".ui-select-focusser"); const getItemsGroups = element => element[0].querySelectorAll(".ui-select-choices-group"); const getItemsGroup = (element, index) => element[0].querySelectorAll(".ui-select-choices-group")[index]; const getItemsGroupLabel = groupElement => groupElement.querySelector(".ui-select-choices-group-label"); @@ -35,11 +35,10 @@ describe("ouiSelect", () => { const element = TestUtils.compileTemplate(` + match="name"> `, { countries: data @@ -55,28 +54,26 @@ describe("ouiSelect", () => { const element = TestUtils.compileTemplate(` + match="name"> `, { countries: data }); - const $container = angular.element(getContainer(element)); const $triggerButton = angular.element(getDropdownButton(element)); // The dropdown should be initially closed. - expect($container.hasClass(openClass)).toBeFalsy(); + expect($triggerButton.attr("aria-expanded")).toBe("false"); // Click on the trigger and check if it's open. $triggerButton.triggerHandler("click"); - expect($container.hasClass(openClass)).toBeTruthy(); + expect($triggerButton.attr("aria-expanded")).toBe("true"); $triggerButton.triggerHandler("click"); - expect($container.hasClass(openClass)).toBeFalsy(); + expect($triggerButton.attr("aria-expanded")).toBe("false"); }); it("should close the dropdown on click outside it", () => { @@ -84,11 +81,10 @@ describe("ouiSelect", () => {
+ match="name"> @@ -96,7 +92,6 @@ describe("ouiSelect", () => { countries: data }); - const $container = angular.element(getContainer(element)); const $triggerButton = angular.element(getDropdownButton(element)); const outsideElement = element[0].querySelector(".outside-button"); @@ -105,28 +100,26 @@ describe("ouiSelect", () => { // Close the dropdown by clicking outside the dropdown. $document.triggerHandler({ type: "click", target: outsideElement }); - expect($container.hasClass(openClass)).toBeFalsy(); + expect($triggerButton.attr("aria-expanded")).toBe("false"); }); describe("Single select", () => { - it("should open dropdown when trigger button is clicked", () => { + it("should close dropdown when item is select", () => { const element = TestUtils.compileTemplate(` + match="name"> `, { countries: data }); - const $container = angular.element(getContainer(element)); const $triggerButton = angular.element(getDropdownButton(element)); - expect($container.hasClass(openClass)).toBeFalsy(); + expect($triggerButton.attr("aria-expanded")).toBe("false"); // Open the dropdown $triggerButton.triggerHandler("click"); @@ -135,13 +128,13 @@ describe("ouiSelect", () => { let $itemButton = angular.element(getDropdownItem(element, 4)); // eslint-disable-line no-magic-numbers expect($itemButton.hasClass(selectedItemClass)).toBeFalsy(); $itemButton.triggerHandler("click"); - expect($itemButton.hasClass(selectedItemClass)).toBeTruthy(); - // By the way, the dropdown should have been closed. - expect($container.hasClass(openClass)).toBeFalsy(); + // The dropdown should have been closed. + expect($triggerButton.attr("aria-expanded")).toBe("false"); // Reopen dropdown and check if the selected element is highlighted. // The element is retrieved again to be sure to not test on a detached element. + $triggerButton.triggerHandler("click"); $itemButton = angular.element(getDropdownItem(element, 4)); // eslint-disable-line no-magic-numbers expect($itemButton.hasClass(selectedItemClass)).toBeTruthy(); }); @@ -152,16 +145,19 @@ describe("ouiSelect", () => { const element = TestUtils.compileTemplate(` + match="name"> `, { countries: data }); + // Must open the select first, to init the dropdown menu + const $triggerButton = angular.element(getDropdownButton(element)); + $triggerButton.triggerHandler("click"); + expect(getDropdownItems(element).length).toEqual(data.length); expect(angular.element(getDropdownItem(element, 0)).text()).toContain(data[0].name); expect(angular.element(getDropdownItem(element, data.length - 1)).text()).toContain(data[data.length - 1].name); @@ -172,15 +168,18 @@ describe("ouiSelect", () => { const stringArray = ["a", "b", "c"]; const element = TestUtils.compileTemplate(` + items="$ctrl.array"> `, { array: stringArray }); + // Must open the select first, to init the dropdown menu + const $triggerButton = angular.element(getDropdownButton(element)); + $triggerButton.triggerHandler("click"); + expect(getDropdownItems(element).length).toEqual(stringArray.length); expect(angular.element(getDropdownItem(element, 0)).text()).toContain(stringArray[0]); expect(angular.element(getDropdownItem(element, stringArray.length - 1)).text()).toContain(stringArray[stringArray.length - 1]); @@ -194,18 +193,21 @@ describe("ouiSelect", () => { const element = TestUtils.compileTemplate(` + group-by="$ctrl.groupByFirstLetter"> `, { countries: data, groupByFirstLetter }); + // Must open the select first, to init the dropdown menu + const $triggerButton = angular.element(getDropdownButton(element)); + $triggerButton.triggerHandler("click"); + const groups = uniq(data.map(groupByFirstLetter)); const firstGroupElement = getItemsGroup(element, 0); const lastGroupElement = getItemsGroup(element, groups.length - 1); @@ -223,7 +225,7 @@ describe("ouiSelect", () => { const element = TestUtils.compileTemplate(` { onBlur }); - angular.element(getDropdownButton(element)).triggerHandler("blur"); + $timeout.flush(); + + angular.element(getFocusser(element)).triggerHandler("blur"); expect(onBlur).toHaveBeenCalled(); }); }); @@ -244,7 +248,7 @@ describe("ouiSelect", () => { const element = TestUtils.compileTemplate(` { onFocus }); - angular.element(getDropdownButton(element)).triggerHandler("focus"); + $timeout.flush(); + + angular.element(getFocusser(element)).triggerHandler("focus"); expect(onFocus).toHaveBeenCalled(); }); }); @@ -265,7 +271,7 @@ describe("ouiSelect", () => { const element = TestUtils.compileTemplate(` { onChange }); - const index1 = 4; - const index2 = 10; - let $itemButton = angular.element(getDropdownItem(element, index1)); - $itemButton.triggerHandler("click"); $timeout.flush(); - expect(onChange).toHaveBeenCalledWith(data[index1]); - $itemButton = angular.element(getDropdownItem(element, index2)); + // Must open the select first, to init the dropdown menu + const $triggerButton = angular.element(getDropdownButton(element)); + $triggerButton.triggerHandler("click"); + + const index = 4; + const $itemButton = angular.element(getDropdownItem(element, index)); $itemButton.triggerHandler("click"); + + // onSelect from ui-select is inside a $timeout $timeout.flush(); - expect(onChange).toHaveBeenCalledWith(data[index2]); + expect(onChange).toHaveBeenCalledWith(data[index]); }); }); diff --git a/packages/oui-select/src/select.controller.js b/packages/oui-select/src/select.controller.js index 46e10231..dba95366 100644 --- a/packages/oui-select/src/select.controller.js +++ b/packages/oui-select/src/select.controller.js @@ -1,8 +1,5 @@ import { addBooleanParameter } from "@ovh-ui/common/component-utils"; -const UI_SELECT_SELECTOR = ".oui-ui-select-container"; -const UI_SELECT_DROPDOWN_TRIGGER = ".oui-button_dropdown"; - export default class { constructor ($attrs, $compile, $element, $scope, $timeout) { "ngInject"; @@ -17,32 +14,29 @@ export default class { $onInit () { addBooleanParameter(this, "disabled"); addBooleanParameter(this, "required"); + addBooleanParameter(this, "searchable"); } $postLink () { const $htmlContent = angular.element(this.htmlContent); - const matchElement = $htmlContent.find("oui-ui-select-match"); - - if (this.match) { - matchElement.html(`{{$select.selected.${this.match}}}`); - } else { - matchElement.html("{{$select.selected}}"); - } - this.$compile($htmlContent)(this.$scope, (clone) => { this.$element.append(clone); }); this.$timeout(() => { - this.$element.removeAttr("name"); + this.$element + .removeAttr("name") + .removeAttr("title"); - this.uiSelectElement = this.$element[0].querySelector(UI_SELECT_SELECTOR); - this.uiSelectDropdownTrigger = this.$element[0].querySelector(UI_SELECT_DROPDOWN_TRIGGER); - - this.unregisterFocus = this.$scope.$on("oui:focus", () => { - this.uiSelectDropdownTrigger.focus(); - }); + this.$select.focusser + .on("blur", () => this.onUiSelectBlur()) + .on("focus", () => this.onUiSelectFocus()); }); + + this.unregisterFocus = this.$scope.$on("oui:focus", () => this.$select.setFocus()); + + // Fix this issue: https://github.com/angular-ui/ui-select/issues/1355 + this.tagHandler = () => null; } $destroy () { @@ -54,7 +48,7 @@ export default class { onUiSelectBlur () { if (this.fieldCtrl) { this.fieldCtrl.hasFocus = false; - this.fieldCtrl.checkControlErrors(this.uiSelectElement, this.name); + this.fieldCtrl.checkControlErrors(this.$select.$element[0], this.name); } this.onBlur(); @@ -63,7 +57,7 @@ export default class { onUiSelectFocus () { if (this.fieldCtrl) { this.fieldCtrl.hasFocus = true; - this.fieldCtrl.hideErrors(this.uiSelectElement, this.name); + this.fieldCtrl.hideErrors(this.$select.$element[0], this.name); } this.onFocus(); diff --git a/packages/oui-select/src/select.directive.js b/packages/oui-select/src/select.directive.js index 45a76cd9..20aa8d0e 100644 --- a/packages/oui-select/src/select.directive.js +++ b/packages/oui-select/src/select.directive.js @@ -12,25 +12,27 @@ export default () => ({ scope: { model: "=", name: "@?", - required: " { - const itemTemplate = $element.html(); + const itemTemplate = $element.html().trim(); const $template = angular.element(template); - const choicesElement = $template.find("oui-ui-select-choices"); + const choicesElement = $template.find("ui-select-choices"); - choicesElement.html(itemTemplate); + if (itemTemplate) { + choicesElement.html(itemTemplate); + } if ($attrs.groupBy) { choicesElement.attr("group-by", "$ctrl.groupBy"); } diff --git a/packages/oui-select/src/select.html b/packages/oui-select/src/select.html index 3fc01767..055cd862 100644 --- a/packages/oui-select/src/select.html +++ b/packages/oui-select/src/select.html @@ -1,13 +1,17 @@ - - - - + on-select="$ctrl.onChange({ modelValue: $model })" + tagging="$ctrl.tagHandler" + search-enabled="{{::!!$ctrl.searchable}}" + theme="oui-ui-select"> + + + + + diff --git a/packages/oui-select/src/templates/choices.html b/packages/oui-select/src/templates/choices.html index 80888d58..768e6c5a 100644 --- a/packages/oui-select/src/templates/choices.html +++ b/packages/oui-select/src/templates/choices.html @@ -1,19 +1,22 @@
    -
  • - -
  • diff --git a/packages/oui-select/src/templates/footer.html b/packages/oui-select/src/templates/footer.html new file mode 100644 index 00000000..2eb79699 --- /dev/null +++ b/packages/oui-select/src/templates/footer.html @@ -0,0 +1 @@ + diff --git a/packages/oui-select/src/templates/header.html b/packages/oui-select/src/templates/header.html new file mode 100644 index 00000000..4883b633 --- /dev/null +++ b/packages/oui-select/src/templates/header.html @@ -0,0 +1 @@ +
    diff --git a/packages/oui-select/src/templates/match-multiple.html b/packages/oui-select/src/templates/match-multiple.html new file mode 100644 index 00000000..04def96c --- /dev/null +++ b/packages/oui-select/src/templates/match-multiple.html @@ -0,0 +1,16 @@ + + + +  × + + + + diff --git a/packages/oui-select/src/templates/match.html b/packages/oui-select/src/templates/match.html index d73c63b0..58592796 100644 --- a/packages/oui-select/src/templates/match.html +++ b/packages/oui-select/src/templates/match.html @@ -1,15 +1,23 @@ - diff --git a/packages/oui-select/src/templates/no-choice.html b/packages/oui-select/src/templates/no-choice.html new file mode 100644 index 00000000..ae611c03 --- /dev/null +++ b/packages/oui-select/src/templates/no-choice.html @@ -0,0 +1,4 @@ +
      +
    • +
    diff --git a/packages/oui-select/src/templates/select-multiple.html b/packages/oui-select/src/templates/select-multiple.html new file mode 100644 index 00000000..bc470935 --- /dev/null +++ b/packages/oui-select/src/templates/select-multiple.html @@ -0,0 +1,24 @@ +
    + +
    +
    +
    +
    + +
    +
    +
    diff --git a/packages/oui-select/src/templates/select.html b/packages/oui-select/src/templates/select.html index 0c2797cc..eef5eea9 100644 --- a/packages/oui-select/src/templates/select.html +++ b/packages/oui-select/src/templates/select.html @@ -1,9 +1,22 @@ -
    -
    - - -
    -
    +
    + +
    +
    +
    +
    +
    -
    +
    diff --git a/packages/oui-select/src/ui-select.js b/packages/oui-select/src/ui-select.js deleted file mode 100644 index ba7a94b9..00000000 --- a/packages/oui-select/src/ui-select.js +++ /dev/null @@ -1,2479 +0,0 @@ -import Popper from "popper.js"; - -/* eslint-disable */ - -/*! - * ui-select - * http://github.com/angular-ui/ui-select - * Version: 0.19.7 - 2017-04-15T14:28:36.649Z - * License: MIT - */ - - -(function () { -"use strict"; -var KEY = { - TAB: 9, - ENTER: 13, - ESC: 27, - SPACE: 32, - LEFT: 37, - UP: 38, - RIGHT: 39, - DOWN: 40, - SHIFT: 16, - CTRL: 17, - ALT: 18, - PAGE_UP: 33, - PAGE_DOWN: 34, - HOME: 36, - END: 35, - BACKSPACE: 8, - DELETE: 46, - COMMAND: 91, - - MAP: { 91 : "COMMAND", 8 : "BACKSPACE" , 9 : "TAB" , 13 : "ENTER" , 16 : "SHIFT" , 17 : "CTRL" , 18 : "ALT" , 19 : "PAUSEBREAK" , 20 : "CAPSLOCK" , 27 : "ESC" , 32 : "SPACE" , 33 : "PAGE_UP", 34 : "PAGE_DOWN" , 35 : "END" , 36 : "HOME" , 37 : "LEFT" , 38 : "UP" , 39 : "RIGHT" , 40 : "DOWN" , 43 : "+" , 44 : "PRINTSCREEN" , 45 : "INSERT" , 46 : "DELETE", 48 : "0" , 49 : "1" , 50 : "2" , 51 : "3" , 52 : "4" , 53 : "5" , 54 : "6" , 55 : "7" , 56 : "8" , 57 : "9" , 59 : ";", 61 : "=" , 65 : "A" , 66 : "B" , 67 : "C" , 68 : "D" , 69 : "E" , 70 : "F" , 71 : "G" , 72 : "H" , 73 : "I" , 74 : "J" , 75 : "K" , 76 : "L", 77 : "M" , 78 : "N" , 79 : "O" , 80 : "P" , 81 : "Q" , 82 : "R" , 83 : "S" , 84 : "T" , 85 : "U" , 86 : "V" , 87 : "W" , 88 : "X" , 89 : "Y" , 90 : "Z", 96 : "0" , 97 : "1" , 98 : "2" , 99 : "3" , 100 : "4" , 101 : "5" , 102 : "6" , 103 : "7" , 104 : "8" , 105 : "9", 106 : "*" , 107 : "+" , 109 : "-" , 110 : "." , 111 : "/", 112 : "F1" , 113 : "F2" , 114 : "F3" , 115 : "F4" , 116 : "F5" , 117 : "F6" , 118 : "F7" , 119 : "F8" , 120 : "F9" , 121 : "F10" , 122 : "F11" , 123 : "F12", 144 : "NUMLOCK" , 145 : "SCROLLLOCK" , 186 : ";" , 187 : "=" , 188 : "," , 189 : "-" , 190 : "." , 191 : "/" , 192 : "`" , 219 : "[" , 220 : "\\" , 221 : "]" , 222 : "'" - }, - - isControl: function (e) { - var k = e.which; - switch (k) { - case KEY.COMMAND: - case KEY.SHIFT: - case KEY.CTRL: - case KEY.ALT: - return true; - } - - if (e.metaKey || e.ctrlKey || e.altKey) return true; - - return false; - }, - isFunctionKey: function (k) { - k = k.which ? k.which : k; - return k >= 112 && k <= 123; - }, - isVerticalMovement: function (k){ - return ~[KEY.UP, KEY.DOWN].indexOf(k); - }, - isHorizontalMovement: function (k){ - return ~[KEY.LEFT,KEY.RIGHT,KEY.BACKSPACE,KEY.DELETE].indexOf(k); - }, - toSeparator: function (k) { - var sep = {ENTER:"\n",TAB:"\t",SPACE:" "}[k]; - if (sep) return sep; - // return undefined for special keys other than enter, tab or space. - // no way to use them to cut strings. - return KEY[k] ? undefined : k; - } - }; - -function isNil(value) { - return angular.isUndefined(value) || value === null; -} - -/** - * Add querySelectorAll() to jqLite. - * - * jqLite find() is limited to lookups by tag name. - * TODO This will change with future versions of AngularJS, to be removed when this happens - * - * See jqLite.find - why not use querySelectorAll? https://github.com/angular/angular.js/issues/3586 - * See feat(jqLite): use querySelectorAll instead of getElementsByTagName in jqLite.find https://github.com/angular/angular.js/pull/3598 - */ -if (angular.element.prototype.querySelectorAll === undefined) { - angular.element.prototype.querySelectorAll = function(selector) { - return angular.element(this[0].querySelectorAll(selector)); - }; -} - -/** - * Add closest() to jqLite. - */ -if (angular.element.prototype.closest === undefined) { - angular.element.prototype.closest = function( selector) { - var elem = this[0]; - var matchesSelector = elem.matches || elem.webkitMatchesSelector || elem.mozMatchesSelector || elem.msMatchesSelector; - - while (elem) { - if (matchesSelector.bind(elem)(selector)) { - return elem; - } else { - elem = elem.parentElement; - } - } - return false; - }; -} - -var latestId = 0; - -var uis = angular.module('oui.ui-select', []) - -.constant('ouiUiSelectConfig', { - theme: 'oui.ui-select', - searchEnabled: true, - sortable: false, - placeholder: '', // Empty by default, like HTML tag "); - $compile(focusser)(scope); - $select.focusser = focusser; - - //Input that will handle focus - $select.focusInput = focusser; - - element.parent().append(focusser); - focusser.bind("focus", function(){ - scope.$evalAsync(function(){ - $select.focus = true; - }); - }); - focusser.bind("blur", function(){ - scope.$evalAsync(function(){ - $select.focus = false; - }); - }); - focusser.bind("keydown", function(e){ - - if (e.which === KEY.BACKSPACE && $select.backspaceReset !== false) { - e.preventDefault(); - e.stopPropagation(); - $select.select(undefined); - scope.$apply(); - return; - } - - if (e.which === KEY.TAB || KEY.isControl(e) || KEY.isFunctionKey(e) || e.which === KEY.ESC) { - return; - } - - if (e.which == KEY.DOWN || e.which == KEY.UP || e.which == KEY.ENTER || e.which == KEY.SPACE){ - e.preventDefault(); - e.stopPropagation(); - $select.activate(); - } - - scope.$digest(); - }); - - focusser.bind("keyup input", function(e){ - - if (e.which === KEY.TAB || KEY.isControl(e) || KEY.isFunctionKey(e) || e.which === KEY.ESC || e.which == KEY.ENTER || e.which === KEY.BACKSPACE) { - return; - } - - $select.activate(focusser.val()); //User pressed some regular key, so we pass it to the search input - focusser.val(''); - scope.$digest(); - - }); - - - } - }; -}]); - -// Make multiple matches sortable -uis.directive('ouiUiSelectSort', ['$timeout', 'ouiUiSelectConfig', 'ouiUiSelectMinErr', function($timeout, ouiUiSelectConfig, ouiUiSelectMinErr) { - return { - require: ['^^ouiUiSelect', '^ngModel'], - link: function(scope, element, attrs, ctrls) { - if (scope[attrs.ouiUiSelectSort] === null) { - throw ouiUiSelectMinErr('sort', 'Expected a list to sort'); - } - - var $select = ctrls[0]; - var $ngModel = ctrls[1]; - - var options = angular.extend({ - axis: 'horizontal' - }, - scope.$eval(attrs.ouiUiSelectSortOptions)); - - var axis = options.axis; - var draggingClassName = 'dragging'; - var droppingClassName = 'dropping'; - var droppingBeforeClassName = 'dropping-before'; - var droppingAfterClassName = 'dropping-after'; - - scope.$watch(function(){ - return $select.sortable; - }, function(newValue){ - if (newValue) { - element.attr('draggable', true); - } else { - element.removeAttr('draggable'); - } - }); - - element.on('dragstart', function(event) { - element.addClass(draggingClassName); - - (event.dataTransfer || event.originalEvent.dataTransfer).setData('text', scope.$index.toString()); - }); - - element.on('dragend', function() { - removeClass(draggingClassName); - }); - - var move = function(from, to) { - /*jshint validthis: true */ - this.splice(to, 0, this.splice(from, 1)[0]); - }; - - var removeClass = function(className) { - angular.forEach($select.$element.querySelectorAll('.' + className), function(el){ - angular.element(el).removeClass(className); - }); - }; - - var dragOverHandler = function(event) { - event.preventDefault(); - - var offset = axis === 'vertical' ? event.offsetY || event.layerY || (event.originalEvent ? event.originalEvent.offsetY : 0) : event.offsetX || event.layerX || (event.originalEvent ? event.originalEvent.offsetX : 0); - - if (offset < (this[axis === 'vertical' ? 'offsetHeight' : 'offsetWidth'] / 2)) { - removeClass(droppingAfterClassName); - element.addClass(droppingBeforeClassName); - - } else { - removeClass(droppingBeforeClassName); - element.addClass(droppingAfterClassName); - } - }; - - var dropTimeout; - - var dropHandler = function(event) { - event.preventDefault(); - - var droppedItemIndex = parseInt((event.dataTransfer || event.originalEvent.dataTransfer).getData('text'), 10); - - // prevent event firing multiple times in firefox - $timeout.cancel(dropTimeout); - dropTimeout = $timeout(function() { - _dropHandler(droppedItemIndex); - }, 20); - }; - - var _dropHandler = function(droppedItemIndex) { - var theList = scope.$eval(attrs.ouiUiSelectSort); - var itemToMove = theList[droppedItemIndex]; - var newIndex = null; - - if (element.hasClass(droppingBeforeClassName)) { - if (droppedItemIndex < scope.$index) { - newIndex = scope.$index - 1; - } else { - newIndex = scope.$index; - } - } else { - if (droppedItemIndex < scope.$index) { - newIndex = scope.$index; - } else { - newIndex = scope.$index + 1; - } - } - - move.apply(theList, [droppedItemIndex, newIndex]); - - $ngModel.$setViewValue(Date.now()); - - scope.$apply(function() { - scope.$emit('ouiUiSelectSort:change', { - array: theList, - item: itemToMove, - from: droppedItemIndex, - to: newIndex - }); - }); - - removeClass(droppingClassName); - removeClass(droppingBeforeClassName); - removeClass(droppingAfterClassName); - - element.off('drop', dropHandler); - }; - - element.on('dragenter', function() { - if (element.hasClass(draggingClassName)) { - return; - } - - element.addClass(droppingClassName); - - element.on('dragover', dragOverHandler); - element.on('drop', dropHandler); - }); - - element.on('dragleave', function(event) { - if (event.target != element) { - return; - } - - removeClass(droppingClassName); - removeClass(droppingBeforeClassName); - removeClass(droppingAfterClassName); - - element.off('dragover', dragOverHandler); - element.off('drop', dropHandler); - }); - } - }; -}]); - -uis.directive('ouiUisOpenClose', ['$parse', '$timeout', function ($parse, $timeout) { - return { - restrict: 'A', - require: 'ouiUiSelect', - link: function (scope, element, attrs, $select) { - $select.onOpenCloseCallback = $parse(attrs.ouiUisOpenClose); - - scope.$watch('$select.open', function (isOpen, previousState) { - if (isOpen !== previousState) { - $timeout(function () { - $select.onOpenCloseCallback(scope, { - isOpen: isOpen - }); - }); - } - }); - } - }; -}]); - -/** - * Parses "repeat" attribute. - * - * Taken from AngularJS ngRepeat source code - * See https://github.com/angular/angular.js/blob/v1.2.15/src/ng/directive/ngRepeat.js#L211 - * - * Original discussion about parsing "repeat" attribute instead of fully relying on ng-repeat: - * https://github.com/angular-ui/ui-select/commit/5dd63ad#commitcomment-5504697 - */ - -uis.service('ouiUisRepeatParser', ['ouiUiSelectMinErr','$parse', function(ouiUiSelectMinErr, $parse) { - var self = this; - - /** - * Example: - * expression = "address in addresses | filter: {street: $select.search} track by $index" - * itemName = "address", - * source = "addresses | filter: {street: $select.search}", - * trackByExp = "$index", - */ - self.parse = function(expression) { - - - var match; - //var isObjectCollection = /\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)/.test(expression); - // If an array is used as collection - - // if (isObjectCollection){ - // 000000000000000000000000000000111111111000000000000000222222222222220033333333333333333333330000444444444444444444000000000000000055555555555000000000000000000000066666666600000000 - match = expression.match(/^\s*(?:([\s\S]+?)\s+as\s+)?(?:([\$\w][\$\w]*)|(?:\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)))\s+in\s+(\s*[\s\S]+?)?(?:\s+track\s+by\s+([\s\S]+?))?\s*$/); - - // 1 Alias - // 2 Item - // 3 Key on (key,value) - // 4 Value on (key,value) - // 5 Source expression (including filters) - // 6 Track by - - if (!match) { - throw ouiUiSelectMinErr('iexp', "Expected expression in form of '_item_ in _collection_[ track by _id_]' but got '{0}'.", - expression); - } - - var source = match[5], - filters = ''; - - // When using (key,value) ui-select requires filters to be extracted, since the object - // is converted to an array for $select.items - // (in which case the filters need to be reapplied) - if (match[3]) { - // Remove any enclosing parenthesis - source = match[5].replace(/(^\()|(\)$)/g, ''); - // match all after | but not after || - var filterMatch = match[5].match(/^\s*(?:[\s\S]+?)(?:[^\|]|\|\|)+([\s\S]*)\s*$/); - if(filterMatch && filterMatch[1].trim()) { - filters = filterMatch[1]; - source = source.replace(filters, ''); - } - } - - return { - itemName: match[4] || match[2], // (lhs) Left-hand side, - keyName: match[3], //for (key, value) syntax - source: $parse(source), - filters: filters, - trackByExp: match[6], - modelMapper: $parse(match[1] || match[4] || match[2]), - repeatExpression: function (grouped) { - var expression = this.itemName + ' in ' + (grouped ? '$group.items' : '$select.items'); - if (this.trackByExp) { - expression += ' track by ' + this.trackByExp; - } - return expression; - } - }; - - }; - - self.getGroupNgRepeatExpression = function() { - return '$group in $select.groups track by $group.name'; - }; - -}]); - -}()); -angular.module("oui.ui-select") - .run(["$templateCache", function($templateCache) { - $templateCache.put("oui.ui-select/choices.tpl.html", require("./templates/choices.html")); - $templateCache.put("oui.ui-select/match-multiple.tpl.html"," × "); - $templateCache.put("oui.ui-select/match.tpl.html", require("./templates/match.html")); - $templateCache.put("oui.ui-select/no-choice.tpl.html","
    "); - $templateCache.put("oui.ui-select/select-multiple.tpl.html","
    "); - $templateCache.put("oui.ui-select/select.tpl.html", require("./templates/select.html")); - }]); diff --git a/yarn.lock b/yarn.lock index f683cf01..bed9b58d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7557,6 +7557,11 @@ uglifyjs-webpack-plugin@^1.2.4: webpack-sources "^1.1.0" worker-farm "^1.5.2" +ui-select@^0.19.8: + version "0.19.8" + resolved "https://registry.yarnpkg.com/ui-select/-/ui-select-0.19.8.tgz#74860848a7fd8bc494d9856d2f62776ea98637c1" + integrity sha1-dIYISKf9i8SU2YVtL2J3bqmGN8E= + ultron@~1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.1.1.tgz#9fe1536a10a664a65266a1e3ccf85fd36302bc9c" From f4720d85d85d8fb987f82fbc65933f583cdfa5d4 Mon Sep 17 00:00:00 2001 From: Axel Peter Date: Wed, 5 Dec 2018 17:43:38 +0100 Subject: [PATCH 2/2] style: code review --- packages/oui-file/src/index.spec.js | 11 ----------- packages/oui-select-picker/src/index.spec.js | 6 ++++++ packages/oui-select/src/index.spec.js | 2 ++ packages/oui-select/src/select.controller.js | 3 --- packages/oui-select/src/select.html | 1 - packages/oui-select/src/templates/match.html | 5 ++--- 6 files changed, 10 insertions(+), 18 deletions(-) diff --git a/packages/oui-file/src/index.spec.js b/packages/oui-file/src/index.spec.js index e5b921cc..78fb909e 100644 --- a/packages/oui-file/src/index.spec.js +++ b/packages/oui-file/src/index.spec.js @@ -255,17 +255,6 @@ describe("ouiFile", () => { controller.removeFile(mockFile); expect(controller.model.length).toBe(0); }); - - it("should load a preview", (done) => { - const delay = 500; - controller.preview = true; - const file = controller.loadFilePreview(mockFile); - setTimeout(() => { - expect(file.loading).toBeTruthy(); - expect(file.reader).toBeDefined(); - done(); - }, delay); - }); }); describe("Form controls", () => { diff --git a/packages/oui-select-picker/src/index.spec.js b/packages/oui-select-picker/src/index.spec.js index 2a9fe0df..c8f8f9c1 100644 --- a/packages/oui-select-picker/src/index.spec.js +++ b/packages/oui-select-picker/src/index.spec.js @@ -257,6 +257,9 @@ describe("ouiSelectPicker", () => { const $choiceElement1 = angular.element(selectPickerComponent1.querySelector(".ui-select-choices-row")); $choiceElement1.triggerHandler("click"); + + // Must open the dropdown before flushing the $timeout + $triggerElement1.triggerHandler("click"); $timeout.flush(); expect(onChangeSpy).toHaveBeenCalledWith("aValue"); @@ -267,6 +270,9 @@ describe("ouiSelectPicker", () => { const $choicesElement2 = angular.element(selectPickerComponent2.querySelector(".ui-select-choices-row")); $choicesElement2.triggerHandler("click"); + + // Must open the dropdown before flushing the $timeout + $triggerElement2.triggerHandler("click"); $timeout.flush(); expect(onChangeSpy).toHaveBeenCalledWith("cValue"); diff --git a/packages/oui-select/src/index.spec.js b/packages/oui-select/src/index.spec.js index f07492ed..604f4ed2 100644 --- a/packages/oui-select/src/index.spec.js +++ b/packages/oui-select/src/index.spec.js @@ -293,6 +293,8 @@ describe("ouiSelect", () => { $itemButton.triggerHandler("click"); // onSelect from ui-select is inside a $timeout + // Must open the dropdown before flushing the $timeout + $triggerButton.triggerHandler("click"); $timeout.flush(); expect(onChange).toHaveBeenCalledWith(data[index]); }); diff --git a/packages/oui-select/src/select.controller.js b/packages/oui-select/src/select.controller.js index dba95366..76fcc69a 100644 --- a/packages/oui-select/src/select.controller.js +++ b/packages/oui-select/src/select.controller.js @@ -34,9 +34,6 @@ export default class { }); this.unregisterFocus = this.$scope.$on("oui:focus", () => this.$select.setFocus()); - - // Fix this issue: https://github.com/angular-ui/ui-select/issues/1355 - this.tagHandler = () => null; } $destroy () { diff --git a/packages/oui-select/src/select.html b/packages/oui-select/src/select.html index 055cd862..6b388bf4 100644 --- a/packages/oui-select/src/select.html +++ b/packages/oui-select/src/select.html @@ -6,7 +6,6 @@ ng-required="$ctrl.required && !$select.open" ng-disabled="$ctrl.disabled" on-select="$ctrl.onChange({ modelValue: $model })" - tagging="$ctrl.tagHandler" search-enabled="{{::!!$ctrl.searchable}}" theme="oui-ui-select"> diff --git a/packages/oui-select/src/templates/match.html b/packages/oui-select/src/templates/match.html index 58592796..4cff7035 100644 --- a/packages/oui-select/src/templates/match.html +++ b/packages/oui-select/src/templates/match.html @@ -7,9 +7,8 @@ ng-click="$select.activate()" tabindex="-1" type="button"> - +