From 39f3dbd945af19d7e1bdc165d2ecf17f256b7e2f Mon Sep 17 00:00:00 2001 From: Joffrey JAFFEUX Date: Tue, 21 Nov 2017 11:53:09 +0100 Subject: [PATCH] Introduces select-kit * renames `select-box-kit` into `select-kit` * introduces `single-select` and `multi-select` as base components * introduces {{search-advanced-category-chooser}} as a better component for selecting category in advanced search * improves events handling in select-kit * recreates color selection inputs using {{multi-select}} and a custom {{selected-color}} component * replaces category-selector by a component using select-kit and based on multi-select * improves positioning of wrapper * removes the need for offscreen, and instead use `select-kit-header` as a base focus point for all select-kit based components * introduces a formal plugin api for select-kit based components * introduces a formal pattern for loading and updating select-kit based components: ``` computeValue() computeContent() mutateValue() ``` --- .eslintrc | 12 +- .../site-settings/category-list.hbs | 2 +- .../admin/templates/web-hooks-show.hbs | 2 +- app/assets/javascripts/application.js | 2 +- .../discourse-common/lib/icon-library.js.es6 | 21 +- .../components/category-selector.js.es6 | 49 --- .../components/future-date-input.js.es6 | 2 +- .../components/search-advanced-options.js.es6 | 16 +- .../components/topic-timeline.js.es6 | 1 + .../discourse/lib/plugin-api.js.es6 | 16 + .../components/category-selector.hbs | 1 - .../templates/components/d-navigation.hbs | 2 +- .../components/edit-category-general.hbs | 2 + .../components/search-advanced-options.hbs | 2 +- .../components/topic-footer-buttons.hbs | 4 +- .../javascripts/discourse/templates/topic.hbs | 1 + .../discourse/templates/topic/unsubscribe.hbs | 2 +- .../discourse/templates/user/messages.hbs | 2 +- .../widgets/component_connector.js.es6 | 18 +- .../discourse/widgets/topic-timeline.js.es6 | 9 +- .../components/admin-group-selector.js.es6 | 45 --- .../components/category-chooser.js.es6 | 131 ------ .../category-notifications-button.js.es6 | 13 - ...ategory-notifications-button-header.js.es6 | 13 - .../combo-box/combo-box-header.js.es6 | 39 -- .../components/dropdown-select-box.js.es6 | 22 -- .../dropdown-select-box-header.js.es6 | 6 - .../dropdown-select-box-row.js.es6 | 9 - .../future-date-input-selector-header.js.es6 | 14 - .../future-date-input-selector-row.js.es6 | 14 - .../components/list-setting.js.es6 | 55 --- .../components/multi-combo-box.js.es6 | 240 ----------- .../multi-combo-box/selected-color.js.es6 | 8 - .../notifications-button-header.js.es6 | 26 -- .../components/pinned-options.js.es6 | 60 --- .../pinned-options-header.js.es6 | 30 -- .../components/select-box-kit.js.es6 | 328 --------------- .../select-box-kit-collection.js.es6 | 5 - .../select-box-kit-create-row.js.es6 | 10 - .../select-box-kit-header.js.es6 | 28 -- .../select-box-kit-none-row.js.es6 | 10 - .../select-box-kit/select-box-kit-row.js.es6 | 70 ---- .../tag-notifications-button.js.es6 | 12 - .../tag-notifications-button-header.js.es6 | 13 - .../select-box-kit/mixins/keyboard.js.es6 | 222 ----------- .../components/combo-box/combo-box-header.hbs | 15 - .../dropdown-select-box-header.hbs | 18 - .../multi-combo-box-header.hbs | 13 - .../multi-combo-box/selected-name.hbs | 9 - .../select-box-kit/select-box-kit-header.hbs | 7 - .../select-box-kit/select-box-kit-row.hbs | 9 - .../admin-agree-flag-dropdown.js.es6 | 29 +- .../admin-delete-flag-dropdown.js.es6 | 25 +- .../components/admin-group-selector.js.es6 | 51 +++ .../categories-admin-dropdown.js.es6 | 23 +- .../components/category-chooser.js.es6 | 92 +++++ .../category-notifications-button.js.es6 | 20 + .../select-kit/components/category-row.js.es6 | 63 +++ .../components/category-selector.js.es6 | 40 ++ .../components/combo-box.js.es6 | 11 +- .../combo-box/combo-box-header.js.es6 | 21 + .../components/dropdown-select-box.js.es6 | 32 ++ .../dropdown-select-box-header.js.es6 | 15 + .../dropdown-select-box-row.js.es6 | 9 + .../future-date-input-selector.js.es6 | 39 +- .../future-date-input-selector-header.js.es6 | 6 + .../future-date-input-selector-row.js.es6 | 6 + .../future-date-input-selector/mixin.js.es6 | 11 +- .../group-notifications-button.js.es6 | 7 +- .../select-kit/components/list-setting.js.es6 | 54 +++ .../select-kit/components/multi-select.js.es6 | 255 ++++++++++++ .../multi-select/multi-select-header.js.es6} | 14 +- .../multi-select/selected-category.js.es6 | 13 + .../multi-select/selected-color.js.es6 | 11 + .../multi-select}/selected-name.js.es6 | 17 +- .../components/none-category-row.js.es6 | 10 + .../components/notifications-button.js.es6 | 27 +- .../notifications-button-row.js.es6 | 8 +- .../components/pinned-button.js.es6 | 7 +- .../components/pinned-options.js.es6 | 55 +++ .../search-advanced-category-chooser.js.es6 | 20 + .../select-kit/components/select-kit.js.es6 | 239 +++++++++++ .../select-kit/select-kit-collection.js.es6 | 5 + .../select-kit/select-kit-create-row.js.es6 | 10 + .../select-kit/select-kit-filter.js.es6} | 4 +- .../select-kit/select-kit-header.js.es6 | 35 ++ .../select-kit/select-kit-none-row.js.es6 | 10 + .../select-kit/select-kit-row.js.es6 | 58 +++ .../components/single-select.js.es6 | 168 ++++++++ .../tag-notifications-button.js.es6 | 23 ++ .../topic-footer-mobile-dropdown.js.es6 | 30 +- .../topic-notifications-button.js.es6 | 2 +- .../topic-notifications-options.js.es6 | 9 +- .../mixins/dom-helpers.js.es6 | 99 ++--- .../select-kit/mixins/events.js.es6 | 233 +++++++++++ .../select-kit/mixins/plugin-api.js.es6 | 71 ++++ .../mixins/utils.js.es6 | 46 +-- .../templates/components/category-row.hbs | 19 + .../components/combo-box/combo-box-header.hbs | 13 + .../dropdown-select-box-header.hbs | 7 + .../dropdown-select-box-row.hbs | 4 +- .../future-date-input-selector-header.hbs | 14 +- .../future-date-input-selector-row.hbs | 6 +- .../multi-select/multi-select-header.hbs | 13 + .../multi-select/selected-category.hbs | 7 + .../multi-select/selected-color.hbs | 13 + .../components/multi-select/selected-name.hbs | 13 + .../templates/components/pinned-button.hbs | 2 +- .../templates/components/select-kit.hbs} | 41 +- .../select-kit/select-kit-collection.hbs} | 30 +- .../select-kit/select-kit-filter.hbs} | 4 +- .../select-kit/select-kit-header.hbs | 5 + .../components/select-kit/select-kit-row.hbs | 6 + .../components/topic-notifications-button.hbs | 5 +- app/assets/javascripts/wizard-application.js | 2 +- .../wizard/test/acceptance/wizard-test.js.es6 | 2 +- app/assets/stylesheets/common.scss | 2 +- .../stylesheets/common/admin/admin_base.scss | 8 +- .../stylesheets/common/admin/flagging.scss | 4 +- .../stylesheets/common/base/_topic-list.scss | 2 +- .../base/edit-topic-status-update-modal.scss | 2 +- app/assets/stylesheets/common/base/modal.scss | 2 +- .../common/base/notifications-button.scss | 9 - .../categories-admin-dropdown.scss | 12 - .../admin-agree-flag-dropdown.scss | 6 +- .../admin-delete-flag-dropdown.scss | 0 .../select-kit/categories-admin-dropdown.scss | 12 + .../category-chooser.scss | 4 +- .../combo-box.scss | 24 +- .../dropdown-select-box.scss | 76 ++-- .../future-date-input-selector.scss | 2 +- .../legacy-combo-box.scss | 0 .../list-setting.scss | 6 +- .../multi-select.scss} | 82 ++-- .../notifications-button.scss | 6 +- .../pinned-button.scss | 2 +- .../select-kit.scss} | 51 +-- .../topic-notifications-button.scss | 0 app/assets/stylesheets/mobile/topic-list.scss | 2 +- app/assets/stylesheets/wizard.scss | 2 +- config/locales/client.ar.yml | 2 +- config/locales/client.de.yml | 2 +- config/locales/client.el.yml | 2 +- config/locales/client.en.yml | 2 +- config/locales/client.es.yml | 2 +- config/locales/client.fa_IR.yml | 2 +- config/locales/client.fi.yml | 2 +- config/locales/client.fr.yml | 2 +- config/locales/client.it.yml | 2 +- config/locales/client.ja.yml | 2 +- config/locales/client.ko.yml | 2 +- config/locales/client.nb_NO.yml | 2 +- config/locales/client.nl.yml | 2 +- config/locales/client.pl_PL.yml | 2 +- config/locales/client.pt.yml | 2 +- config/locales/client.ru.yml | 2 +- config/locales/client.vi.yml | 2 +- config/locales/client.zh_CN.yml | 2 +- .../acceptance/details-button-test.js.es6 | 10 +- .../widgets/discourse-poll-option-test.js.es6 | 8 +- .../acceptance/admin-flags-test.js.es6 | 24 +- .../acceptance/admin-suspend-user-test.js.es6 | 4 +- .../acceptance/category-chooser-test.js.es6 | 6 +- .../acceptance/category-edit-test.js.es6 | 4 +- .../acceptance/composer-test.js.es6 | 4 +- .../acceptance/search-full-test.js.es6 | 32 +- .../javascripts/acceptance/search-test.js.es6 | 44 +-- .../topic-notifications-button-test.js.es6 | 6 +- test/javascripts/acceptance/topic-test.js.es6 | 12 +- .../categories-admin-dropdown-test.js.es6 | 10 +- .../components/category-chooser-test.js.es6 | 40 +- .../components/categpry-selector-test.js.es6 | 67 ++++ .../components/combo-box-test.js.es6 | 86 ++-- .../components/d-button-test.js.es6 | 4 +- .../components/list-setting-test.js.es6 | 42 +- .../components/multi-combo-box-test.js.es6 | 109 ----- .../components/multi-select-test.js.es6 | 109 +++++ .../components/pinned-button-test.js.es6 | 40 -- .../components/pinned-options-test.js.es6 | 35 ++ .../components/select-box-kit-test.js.es6 | 288 -------------- .../components/single-select-test.js.es6 | 372 ++++++++++++++++++ .../topic-footer-mobile-dropdown-test.js.es6 | 12 +- .../topic-notifications-button-test.js.es6 | 16 +- .../helpers/select-box-kit-helper.js | 146 ------- test/javascripts/helpers/select-kit-helper.js | 149 +++++++ test/javascripts/test_helper.js | 2 +- .../widgets/actions-summary-test.js.es6 | 2 +- test/javascripts/widgets/button-test.js.es6 | 4 +- .../javascripts/widgets/home-logo-test.js.es6 | 2 +- test/javascripts/widgets/post-test.js.es6 | 6 +- .../widgets/poster-name-test.js.es6 | 2 +- 191 files changed, 3160 insertions(+), 2788 deletions(-) delete mode 100644 app/assets/javascripts/discourse/components/category-selector.js.es6 delete mode 100644 app/assets/javascripts/discourse/templates/components/category-selector.hbs delete mode 100644 app/assets/javascripts/select-box-kit/components/admin-group-selector.js.es6 delete mode 100644 app/assets/javascripts/select-box-kit/components/category-chooser.js.es6 delete mode 100644 app/assets/javascripts/select-box-kit/components/category-notifications-button.js.es6 delete mode 100644 app/assets/javascripts/select-box-kit/components/category-notifications-button/category-notifications-button-header.js.es6 delete mode 100644 app/assets/javascripts/select-box-kit/components/combo-box/combo-box-header.js.es6 delete mode 100644 app/assets/javascripts/select-box-kit/components/dropdown-select-box.js.es6 delete mode 100644 app/assets/javascripts/select-box-kit/components/dropdown-select-box/dropdown-select-box-header.js.es6 delete mode 100644 app/assets/javascripts/select-box-kit/components/dropdown-select-box/dropdown-select-box-row.js.es6 delete mode 100644 app/assets/javascripts/select-box-kit/components/future-date-input-selector/future-date-input-selector-header.js.es6 delete mode 100644 app/assets/javascripts/select-box-kit/components/future-date-input-selector/future-date-input-selector-row.js.es6 delete mode 100644 app/assets/javascripts/select-box-kit/components/list-setting.js.es6 delete mode 100644 app/assets/javascripts/select-box-kit/components/multi-combo-box.js.es6 delete mode 100644 app/assets/javascripts/select-box-kit/components/multi-combo-box/selected-color.js.es6 delete mode 100644 app/assets/javascripts/select-box-kit/components/notifications-button/notifications-button-header.js.es6 delete mode 100644 app/assets/javascripts/select-box-kit/components/pinned-options.js.es6 delete mode 100644 app/assets/javascripts/select-box-kit/components/pinned-options/pinned-options-header.js.es6 delete mode 100644 app/assets/javascripts/select-box-kit/components/select-box-kit.js.es6 delete mode 100644 app/assets/javascripts/select-box-kit/components/select-box-kit/select-box-kit-collection.js.es6 delete mode 100644 app/assets/javascripts/select-box-kit/components/select-box-kit/select-box-kit-create-row.js.es6 delete mode 100644 app/assets/javascripts/select-box-kit/components/select-box-kit/select-box-kit-header.js.es6 delete mode 100644 app/assets/javascripts/select-box-kit/components/select-box-kit/select-box-kit-none-row.js.es6 delete mode 100644 app/assets/javascripts/select-box-kit/components/select-box-kit/select-box-kit-row.js.es6 delete mode 100644 app/assets/javascripts/select-box-kit/components/tag-notifications-button.js.es6 delete mode 100644 app/assets/javascripts/select-box-kit/components/tag-notifications-button/tag-notifications-button-header.js.es6 delete mode 100644 app/assets/javascripts/select-box-kit/mixins/keyboard.js.es6 delete mode 100644 app/assets/javascripts/select-box-kit/templates/components/combo-box/combo-box-header.hbs delete mode 100644 app/assets/javascripts/select-box-kit/templates/components/dropdown-select-box/dropdown-select-box-header.hbs delete mode 100644 app/assets/javascripts/select-box-kit/templates/components/multi-combo-box/multi-combo-box-header.hbs delete mode 100644 app/assets/javascripts/select-box-kit/templates/components/multi-combo-box/selected-name.hbs delete mode 100644 app/assets/javascripts/select-box-kit/templates/components/select-box-kit/select-box-kit-header.hbs delete mode 100644 app/assets/javascripts/select-box-kit/templates/components/select-box-kit/select-box-kit-row.hbs rename app/assets/javascripts/{select-box-kit => select-kit}/components/admin-agree-flag-dropdown.js.es6 (76%) rename app/assets/javascripts/{select-box-kit => select-kit}/components/admin-delete-flag-dropdown.js.es6 (74%) create mode 100644 app/assets/javascripts/select-kit/components/admin-group-selector.js.es6 rename app/assets/javascripts/{select-box-kit => select-kit}/components/categories-admin-dropdown.js.es6 (51%) create mode 100644 app/assets/javascripts/select-kit/components/category-chooser.js.es6 create mode 100644 app/assets/javascripts/select-kit/components/category-notifications-button.js.es6 create mode 100644 app/assets/javascripts/select-kit/components/category-row.js.es6 create mode 100644 app/assets/javascripts/select-kit/components/category-selector.js.es6 rename app/assets/javascripts/{select-box-kit => select-kit}/components/combo-box.js.es6 (61%) create mode 100644 app/assets/javascripts/select-kit/components/combo-box/combo-box-header.js.es6 create mode 100644 app/assets/javascripts/select-kit/components/dropdown-select-box.js.es6 create mode 100644 app/assets/javascripts/select-kit/components/dropdown-select-box/dropdown-select-box-header.js.es6 create mode 100644 app/assets/javascripts/select-kit/components/dropdown-select-box/dropdown-select-box-row.js.es6 rename app/assets/javascripts/{select-box-kit => select-kit}/components/future-date-input-selector.js.es6 (79%) create mode 100644 app/assets/javascripts/select-kit/components/future-date-input-selector/future-date-input-selector-header.js.es6 create mode 100644 app/assets/javascripts/select-kit/components/future-date-input-selector/future-date-input-selector-row.js.es6 rename app/assets/javascripts/{select-box-kit => select-kit}/components/future-date-input-selector/mixin.js.es6 (76%) rename app/assets/javascripts/{select-box-kit => select-kit}/components/group-notifications-button.js.es6 (51%) create mode 100644 app/assets/javascripts/select-kit/components/list-setting.js.es6 create mode 100644 app/assets/javascripts/select-kit/components/multi-select.js.es6 rename app/assets/javascripts/{select-box-kit/components/multi-combo-box/multi-combo-box-header.js.es6 => select-kit/components/multi-select/multi-select-header.js.es6} (66%) create mode 100644 app/assets/javascripts/select-kit/components/multi-select/selected-category.js.es6 create mode 100644 app/assets/javascripts/select-kit/components/multi-select/selected-color.js.es6 rename app/assets/javascripts/{select-box-kit/components/multi-combo-box => select-kit/components/multi-select}/selected-name.js.es6 (50%) create mode 100644 app/assets/javascripts/select-kit/components/none-category-row.js.es6 rename app/assets/javascripts/{select-box-kit => select-kit}/components/notifications-button.js.es6 (56%) rename app/assets/javascripts/{select-box-kit => select-kit}/components/notifications-button/notifications-button-row.js.es6 (76%) rename app/assets/javascripts/{select-box-kit => select-kit}/components/pinned-button.js.es6 (71%) create mode 100644 app/assets/javascripts/select-kit/components/pinned-options.js.es6 create mode 100644 app/assets/javascripts/select-kit/components/search-advanced-category-chooser.js.es6 create mode 100644 app/assets/javascripts/select-kit/components/select-kit.js.es6 create mode 100644 app/assets/javascripts/select-kit/components/select-kit/select-kit-collection.js.es6 create mode 100644 app/assets/javascripts/select-kit/components/select-kit/select-kit-create-row.js.es6 rename app/assets/javascripts/{select-box-kit/components/select-box-kit/select-box-kit-filter.js.es6 => select-kit/components/select-kit/select-kit-filter.js.es6} (51%) create mode 100644 app/assets/javascripts/select-kit/components/select-kit/select-kit-header.js.es6 create mode 100644 app/assets/javascripts/select-kit/components/select-kit/select-kit-none-row.js.es6 create mode 100644 app/assets/javascripts/select-kit/components/select-kit/select-kit-row.js.es6 create mode 100644 app/assets/javascripts/select-kit/components/single-select.js.es6 create mode 100644 app/assets/javascripts/select-kit/components/tag-notifications-button.js.es6 rename app/assets/javascripts/{select-box-kit => select-kit}/components/topic-footer-mobile-dropdown.js.es6 (68%) rename app/assets/javascripts/{select-box-kit => select-kit}/components/topic-notifications-button.js.es6 (62%) rename app/assets/javascripts/{select-box-kit => select-kit}/components/topic-notifications-options.js.es6 (79%) rename app/assets/javascripts/{select-box-kit => select-kit}/mixins/dom-helpers.js.es6 (71%) create mode 100644 app/assets/javascripts/select-kit/mixins/events.js.es6 create mode 100644 app/assets/javascripts/select-kit/mixins/plugin-api.js.es6 rename app/assets/javascripts/{select-box-kit => select-kit}/mixins/utils.js.es6 (52%) create mode 100644 app/assets/javascripts/select-kit/templates/components/category-row.hbs create mode 100644 app/assets/javascripts/select-kit/templates/components/combo-box/combo-box-header.hbs create mode 100644 app/assets/javascripts/select-kit/templates/components/dropdown-select-box/dropdown-select-box-header.hbs rename app/assets/javascripts/{select-box-kit => select-kit}/templates/components/dropdown-select-box/dropdown-select-box-row.hbs (78%) rename app/assets/javascripts/{select-box-kit => select-kit}/templates/components/future-date-input-selector/future-date-input-selector-header.hbs (51%) rename app/assets/javascripts/{select-box-kit => select-kit}/templates/components/future-date-input-selector/future-date-input-selector-row.hbs (58%) create mode 100644 app/assets/javascripts/select-kit/templates/components/multi-select/multi-select-header.hbs create mode 100644 app/assets/javascripts/select-kit/templates/components/multi-select/selected-category.hbs create mode 100644 app/assets/javascripts/select-kit/templates/components/multi-select/selected-color.hbs create mode 100644 app/assets/javascripts/select-kit/templates/components/multi-select/selected-name.hbs rename app/assets/javascripts/{select-box-kit => select-kit}/templates/components/pinned-button.hbs (50%) rename app/assets/javascripts/{select-box-kit/templates/components/select-box-kit.hbs => select-kit/templates/components/select-kit.hbs} (56%) rename app/assets/javascripts/{select-box-kit/templates/components/select-box-kit/select-box-kit-collection.hbs => select-kit/templates/components/select-kit/select-kit-collection.hbs} (62%) rename app/assets/javascripts/{select-box-kit/templates/components/select-box-kit/select-box-kit-filter.hbs => select-kit/templates/components/select-kit/select-kit-filter.hbs} (77%) create mode 100644 app/assets/javascripts/select-kit/templates/components/select-kit/select-kit-header.hbs create mode 100644 app/assets/javascripts/select-kit/templates/components/select-kit/select-kit-row.hbs rename app/assets/javascripts/{select-box-kit => select-kit}/templates/components/topic-notifications-button.hbs (50%) delete mode 100644 app/assets/stylesheets/common/base/notifications-button.scss delete mode 100644 app/assets/stylesheets/common/select-box-kit/categories-admin-dropdown.scss rename app/assets/stylesheets/common/{select-box-kit => select-kit}/admin-agree-flag-dropdown.scss (64%) rename app/assets/stylesheets/common/{select-box-kit => select-kit}/admin-delete-flag-dropdown.scss (100%) create mode 100644 app/assets/stylesheets/common/select-kit/categories-admin-dropdown.scss rename app/assets/stylesheets/common/{select-box-kit => select-kit}/category-chooser.scss (92%) rename app/assets/stylesheets/common/{select-box-kit => select-kit}/combo-box.scss (80%) rename app/assets/stylesheets/common/{select-box-kit => select-kit}/dropdown-select-box.scss (67%) rename app/assets/stylesheets/common/{select-box-kit => select-kit}/future-date-input-selector.scss (93%) rename app/assets/stylesheets/common/{select-box-kit => select-kit}/legacy-combo-box.scss (100%) rename app/assets/stylesheets/common/{select-box-kit => select-kit}/list-setting.scss (56%) rename app/assets/stylesheets/common/{select-box-kit/multi-combo-box.scss => select-kit/multi-select.scss} (61%) rename app/assets/stylesheets/common/{select-box-kit => select-kit}/notifications-button.scss (69%) rename app/assets/stylesheets/common/{select-box-kit => select-kit}/pinned-button.scss (94%) rename app/assets/stylesheets/common/{select-box-kit/select-box-kit.scss => select-kit/select-kit.scss} (86%) rename app/assets/stylesheets/common/{select-box-kit => select-kit}/topic-notifications-button.scss (100%) create mode 100644 test/javascripts/components/categpry-selector-test.js.es6 delete mode 100644 test/javascripts/components/multi-combo-box-test.js.es6 create mode 100644 test/javascripts/components/multi-select-test.js.es6 delete mode 100644 test/javascripts/components/pinned-button-test.js.es6 create mode 100644 test/javascripts/components/pinned-options-test.js.es6 delete mode 100644 test/javascripts/components/select-box-kit-test.js.es6 create mode 100644 test/javascripts/components/single-select-test.js.es6 delete mode 100644 test/javascripts/helpers/select-box-kit-helper.js create mode 100644 test/javascripts/helpers/select-kit-helper.js diff --git a/.eslintrc b/.eslintrc index 6f7c9f0ecdd..bfbe34ea65e 100644 --- a/.eslintrc +++ b/.eslintrc @@ -42,12 +42,12 @@ "invisible":true, "asyncRender":true, "selectDropdown":true, - "selectBox":true, - "expandSelectBoxKit":true, - "collapseSelectBoxKit":true, - "selectBoxKitSelectRow":true, - "selectBoxKitSelectNoneRow":true, - "selectBoxKitFillInFilter":true, + "selectKit":true, + "expandSelectKit":true, + "collapseSelectKit":true, + "selectKitSelectRow":true, + "selectKitSelectNoneRow":true, + "selectKitFillInFilter":true, "asyncTestDiscourse":true, "fixture":true, "find":true, diff --git a/app/assets/javascripts/admin/templates/components/site-settings/category-list.hbs b/app/assets/javascripts/admin/templates/components/site-settings/category-list.hbs index 8c0b4eda1e9..0aadec18d81 100644 --- a/app/assets/javascripts/admin/templates/components/site-settings/category-list.hbs +++ b/app/assets/javascripts/admin/templates/components/site-settings/category-list.hbs @@ -1,3 +1,3 @@ -{{category-selector categories=selectedCategories blacklist=selectedCategories}} +{{category-selector categories=selectedCategories}}
{{{unbound setting.description}}}
{{setting-validation-message message=validationMessage}} diff --git a/app/assets/javascripts/admin/templates/web-hooks-show.hbs b/app/assets/javascripts/admin/templates/web-hooks-show.hbs index 53c0cba1467..ef9c478774a 100644 --- a/app/assets/javascripts/admin/templates/web-hooks-show.hbs +++ b/app/assets/javascripts/admin/templates/web-hooks-show.hbs @@ -48,7 +48,7 @@
- {{category-selector categories=model.categories blacklist=model.categories}} + {{category-selector categories=model.categories}}
{{i18n 'admin.web_hooks.categories_filter_instructions'}}
diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 280e12954ee..6b0d64be848 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -4,7 +4,7 @@ //= require ./ember-addons/ember-computed-decorators //= require ./ember-addons/fmt //= require_tree ./discourse-common -//= require_tree ./select-box-kit +//= require_tree ./select-kit //= require ./discourse //= require ./deprecated diff --git a/app/assets/javascripts/discourse-common/lib/icon-library.js.es6 b/app/assets/javascripts/discourse-common/lib/icon-library.js.es6 index 0dcf4051cd8..15001e4ca59 100644 --- a/app/assets/javascripts/discourse-common/lib/icon-library.js.es6 +++ b/app/assets/javascripts/discourse-common/lib/icon-library.js.es6 @@ -42,7 +42,8 @@ export function renderIcon(renderType, id, params) { let rendererForType = renderer[renderType]; if (rendererForType) { - let result = rendererForType(REPLACEMENTS[id] || id, params || {}); + const icon = { id, replacementId: REPLACEMENTS[id] }; + let result = rendererForType(icon, params || {}); if (result) { return result; } @@ -68,8 +69,14 @@ export function registerIconRenderer(renderer) { } // Support for font awesome icons -function faClasses(id, params) { - let classNames = `fa fa-${id} d-icon d-icon-${id}`; +function faClasses(icon, params) { + let classNames; + if (typeof icon.replacementId !== "undefined") { + classNames = `fa fa-${icon.replacementId} d-icon ${icon.id}`; + } else { + classNames = `fa fa-${icon.id} d-icon d-${icon.id}`; + } + if (params) { if (params.modifier) { classNames += " fa-" + params.modifier; } if (params['class']) { classNames += ' ' + params['class']; } @@ -81,9 +88,9 @@ function faClasses(id, params) { registerIconRenderer({ name: 'font-awesome', - string(id, params) { + string(icon, params) { let tagName = params.tagName || 'i'; - let html = `<${tagName} class='${faClasses(id, params)}'`; + let html = `<${tagName} class='${faClasses(icon, params)}'`; if (params.title) { html += ` title='${I18n.t(params.title)}'`; } if (params.label) { html += " aria-hidden='true'"; } html += `>`; @@ -93,11 +100,11 @@ registerIconRenderer({ return html; }, - node(id, params) { + node(icon, params) { let tagName = params.tagName || 'i'; const properties = { - className: faClasses(id, params), + className: faClasses(icon, params), attributes: { "aria-hidden": true } }; diff --git a/app/assets/javascripts/discourse/components/category-selector.js.es6 b/app/assets/javascripts/discourse/components/category-selector.js.es6 deleted file mode 100644 index 9cb3eec14ae..00000000000 --- a/app/assets/javascripts/discourse/components/category-selector.js.es6 +++ /dev/null @@ -1,49 +0,0 @@ -import { categoryBadgeHTML } from 'discourse/helpers/category-link'; -import Category from 'discourse/models/category'; -import { on, observes } from 'ember-addons/ember-computed-decorators'; -import { findRawTemplate } from 'discourse/lib/raw-templates'; - -export default Ember.Component.extend({ - @observes('categories') - _update() { - if (this.get('canReceiveUpdates') === 'true') - this._initializeAutocomplete({updateData: true}); - }, - - @on('didInsertElement') - _initializeAutocomplete(opts) { - const self = this, - regexp = new RegExp(`href=['\"]${Discourse.getURL('/c/')}([^'\"]+)`); - - this.$('input').autocomplete({ - items: this.get('categories'), - single: this.get('single'), - allowAny: false, - updateData: (opts && opts.updateData) ? opts.updateData : false, - dataSource(term) { - return Category.list().filter(category => { - const regex = new RegExp(term, 'i'); - return category.get('name').match(regex) && - !_.contains(self.get('blacklist') || [], category) && - !_.contains(self.get('categories'), category) ; - }); - }, - onChangeItems(items) { - const categories = _.map(items, link => { - const slug = link.match(regexp)[1]; - return Category.findSingleBySlug(slug); - }); - Em.run.next(() => { - let existingCategory = _.isArray(self.get('categories')) ? self.get('categories') : [self.get('categories')]; - const result = _.intersection(existingCategory.map(itm => itm.id), categories.map(itm => itm.id)); - if (result.length !== categories.length || existingCategory.length !== categories.length) - self.set('categories', categories); - }); - }, - template: findRawTemplate('category-selector-autocomplete'), - transformComplete(category) { - return categoryBadgeHTML(category, {allowUncategorized: true}); - } - }); - } -}); diff --git a/app/assets/javascripts/discourse/components/future-date-input.js.es6 b/app/assets/javascripts/discourse/components/future-date-input.js.es6 index 97b87387872..5c9d37527e0 100644 --- a/app/assets/javascripts/discourse/components/future-date-input.js.es6 +++ b/app/assets/javascripts/discourse/components/future-date-input.js.es6 @@ -1,7 +1,7 @@ import { default as computed, observes } from "ember-addons/ember-computed-decorators"; import { FORMAT, -} from "select-box-kit/components/future-date-input-selector"; +} from "select-kit/components/future-date-input-selector"; import { PUBLISH_TO_CATEGORY_STATUS_TYPE } from 'discourse/controllers/edit-topic-timer'; diff --git a/app/assets/javascripts/discourse/components/search-advanced-options.js.es6 b/app/assets/javascripts/discourse/components/search-advanced-options.js.es6 index f29c6f95a39..a171083523d 100644 --- a/app/assets/javascripts/discourse/components/search-advanced-options.js.es6 +++ b/app/assets/javascripts/discourse/components/search-advanced-options.js.es6 @@ -185,18 +185,18 @@ export default Em.Component.extend({ const userInput = Discourse.Category.findBySlug(subcategories[1], subcategories[0]); if ((!existingInput && userInput) || (existingInput && userInput && existingInput.id !== userInput.id)) - this.set('searchedTerms.category', [userInput]); + this.set('searchedTerms.category', userInput); } else if (isNaN(subcategories)) { const userInput = Discourse.Category.findSingleBySlug(subcategories[0]); if ((!existingInput && userInput) || (existingInput && userInput && existingInput.id !== userInput.id)) - this.set('searchedTerms.category', [userInput]); + this.set('searchedTerms.category', userInput); } else { const userInput = Discourse.Category.findById(subcategories[0]); if ((!existingInput && userInput) || (existingInput && userInput && existingInput.id !== userInput.id)) - this.set('searchedTerms.category', [userInput]); + this.set('searchedTerms.category', userInput); } } else this.set('searchedTerms.category', ''); @@ -303,11 +303,11 @@ export default Em.Component.extend({ const slugCategoryMatches = (match.length !== 0) ? match[0].match(REGEXP_CATEGORY_SLUG) : null; const idCategoryMatches = (match.length !== 0) ? match[0].match(REGEXP_CATEGORY_ID) : null; - if (categoryFilter && categoryFilter[0]) { - const id = categoryFilter[0].id; - const slug = categoryFilter[0].slug; - if (categoryFilter[0].parentCategory) { - const parentSlug = categoryFilter[0].parentCategory.slug; + if (categoryFilter) { + const id = categoryFilter.id; + const slug = categoryFilter.slug; + if (categoryFilter.parentCategory) { + const parentSlug = categoryFilter.parentCategory.slug; if (slugCategoryMatches) searchTerm = searchTerm.replace(slugCategoryMatches[0], `#${parentSlug}:${slug}`); else if (idCategoryMatches) diff --git a/app/assets/javascripts/discourse/components/topic-timeline.js.es6 b/app/assets/javascripts/discourse/components/topic-timeline.js.es6 index cfa9340e940..8512ca6794a 100644 --- a/app/assets/javascripts/discourse/components/topic-timeline.js.es6 +++ b/app/assets/javascripts/discourse/components/topic-timeline.js.es6 @@ -12,6 +12,7 @@ export default MountWidget.extend(Docking, { buildArgs() { let attrs = { topic: this.get('topic'), + notificationLevel: this.get('notificationLevel'), topicTrackingState: this.topicTrackingState, enteredIndex: this.get('enteredIndex'), dockAt: this.dockAt, diff --git a/app/assets/javascripts/discourse/lib/plugin-api.js.es6 b/app/assets/javascripts/discourse/lib/plugin-api.js.es6 index 03467421cb9..a674d497f31 100644 --- a/app/assets/javascripts/discourse/lib/plugin-api.js.es6 +++ b/app/assets/javascripts/discourse/lib/plugin-api.js.es6 @@ -21,6 +21,7 @@ import { attachAdditionalPanel } from 'discourse/widgets/header'; import { registerIconRenderer, replaceIcon } from 'discourse-common/lib/icon-library'; import { addNavItem } from 'discourse/models/nav-item'; import { replaceFormatter } from 'discourse/lib/utilities'; +import { modifySelectKit } from "select-kit/mixins/plugin-api"; // If you add any methods to the API ensure you bump up this number const PLUGIN_API_VERSION = '0.8.12'; @@ -589,6 +590,21 @@ class PluginApi { formatUsername(fn) { replaceFormatter(fn); } + + /** + * + * Access SelectKit plugin api + * + * Example: + * + * modifySelectKit("topic-footer-mobile-dropdown").appendContent(() => [{ + * name: "discourse", + * id: 1 + * }]) + */ + modifySelectKit(pluginApiKey) { + return modifySelectKit(pluginApiKey); + } } let _pluginv01; diff --git a/app/assets/javascripts/discourse/templates/components/category-selector.hbs b/app/assets/javascripts/discourse/templates/components/category-selector.hbs deleted file mode 100644 index a265ef5f12b..00000000000 --- a/app/assets/javascripts/discourse/templates/components/category-selector.hbs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/app/assets/javascripts/discourse/templates/components/d-navigation.hbs b/app/assets/javascripts/discourse/templates/components/d-navigation.hbs index dd0fe03f3e6..6f8c71f5249 100644 --- a/app/assets/javascripts/discourse/templates/components/d-navigation.hbs +++ b/app/assets/javascripts/discourse/templates/components/d-navigation.hbs @@ -9,7 +9,7 @@ {{navigation-bar navItems=navItems filterMode=filterMode category=category}} {{#if showCategoryNotifications}} - {{category-notifications-button category=category}} + {{category-notifications-button value=category.notification_level category=category}} {{/if}} {{create-topic-button diff --git a/app/assets/javascripts/discourse/templates/components/edit-category-general.hbs b/app/assets/javascripts/discourse/templates/components/edit-category-general.hbs index 4f89ede6048..c31406819a7 100644 --- a/app/assets/javascripts/discourse/templates/components/edit-category-general.hbs +++ b/app/assets/javascripts/discourse/templates/components/edit-category-general.hbs @@ -22,7 +22,9 @@ {{category-chooser none="category.none" value=category.parent_category_id + excludeCategoryId=category.id categories=parentCategories + allowSubCategories=false allowUncategorized=false}} {{/if}} diff --git a/app/assets/javascripts/discourse/templates/components/search-advanced-options.hbs b/app/assets/javascripts/discourse/templates/components/search-advanced-options.hbs index c1c1914b64a..eb8342b8ded 100644 --- a/app/assets/javascripts/discourse/templates/components/search-advanced-options.hbs +++ b/app/assets/javascripts/discourse/templates/components/search-advanced-options.hbs @@ -13,7 +13,7 @@
- {{category-selector categories=searchedTerms.category single="true" canReceiveUpdates="true"}} + {{search-advanced-category-chooser value=searchedTerms.category}}
diff --git a/app/assets/javascripts/discourse/templates/components/topic-footer-buttons.hbs b/app/assets/javascripts/discourse/templates/components/topic-footer-buttons.hbs index a4dcf9987ab..048cff64c98 100644 --- a/app/assets/javascripts/discourse/templates/components/topic-footer-buttons.hbs +++ b/app/assets/javascripts/discourse/templates/components/topic-footer-buttons.hbs @@ -74,10 +74,10 @@ args=(hash topic=topic) connectorTagName="span"}} - {{pinned-button topic=topic}} + {{pinned-button pinned=topic.pinned topic=topic}}
-{{topic-notifications-button topic=topic}} +{{topic-notifications-button notificationLevel=topic.details.notification_level topic=topic}} {{plugin-outlet name="after-topic-footer-buttons" args=(hash topic=topic) diff --git a/app/assets/javascripts/discourse/templates/topic.hbs b/app/assets/javascripts/discourse/templates/topic.hbs index f26c41d6414..281ffd8f135 100644 --- a/app/assets/javascripts/discourse/templates/topic.hbs +++ b/app/assets/javascripts/discourse/templates/topic.hbs @@ -85,6 +85,7 @@ {{topic-timeline topic=model + notificationLevel=model.details.notification_level prevEvent=info.prevEvent fullscreen=info.topicProgressExpanded enteredIndex=enteredIndex diff --git a/app/assets/javascripts/discourse/templates/topic/unsubscribe.hbs b/app/assets/javascripts/discourse/templates/topic/unsubscribe.hbs index 54947fbdaaa..17a4df882eb 100644 --- a/app/assets/javascripts/discourse/templates/topic/unsubscribe.hbs +++ b/app/assets/javascripts/discourse/templates/topic/unsubscribe.hbs @@ -8,6 +8,6 @@ {{i18n "topic.unsubscribe.change_notification_state"}}

- {{topic-notifications-button topic=model}} + {{topic-notifications-button notificationLevel=model.details.notification_level topic=model}} diff --git a/app/assets/javascripts/discourse/templates/user/messages.hbs b/app/assets/javascripts/discourse/templates/user/messages.hbs index 3e19ee722a1..5a788282337 100644 --- a/app/assets/javascripts/discourse/templates/user/messages.hbs +++ b/app/assets/javascripts/discourse/templates/user/messages.hbs @@ -73,7 +73,7 @@ {{/if}} {{#if isGroup}} - {{group-notifications-button group=group user=model}} + {{group-notifications-button value=group.group_user.notification_level group=group user=model}} {{/if}} diff --git a/app/assets/javascripts/discourse/widgets/component_connector.js.es6 b/app/assets/javascripts/discourse/widgets/component_connector.js.es6 index 7484fad179d..e603896883c 100644 --- a/app/assets/javascripts/discourse/widgets/component_connector.js.es6 +++ b/app/assets/javascripts/discourse/widgets/component_connector.js.es6 @@ -1,12 +1,13 @@ export default class ComponentConnector { - constructor(widget, componentName, opts) { + constructor(widget, componentName, opts, trackedProperties) { this.widget = widget; this.opts = opts; this.componentName = componentName; + this.trackedProperties = trackedProperties || []; } init() { - const $elem = $('
'); + const $elem = $('
'); const elem = $elem[0]; const { opts, widget, componentName } = this; @@ -29,7 +30,18 @@ export default class ComponentConnector { return elem; } - update() { } + update(prev) { + let shouldInit = false; + this.trackedProperties.forEach(prop => { + if (prev.opts[prop] !== this.opts[prop]) { + shouldInit = true; + } + }); + + if (shouldInit === true) return this.init(); + + return null; + } } ComponentConnector.prototype.type = 'Widget'; diff --git a/app/assets/javascripts/discourse/widgets/topic-timeline.js.es6 b/app/assets/javascripts/discourse/widgets/topic-timeline.js.es6 index 2fb698a38c8..ebe27426c52 100644 --- a/app/assets/javascripts/discourse/widgets/topic-timeline.js.es6 +++ b/app/assets/javascripts/discourse/widgets/topic-timeline.js.es6 @@ -291,7 +291,7 @@ createWidget('timeline-footer-controls', { html(attrs) { const controls = []; - const { currentUser, fullScreen, topic } = attrs; + const { currentUser, fullScreen, topic, notificationLevel } = attrs; if (currentUser && !fullScreen) { if (topic.get('details.can_create_post')) { @@ -315,12 +315,13 @@ createWidget('timeline-footer-controls', { if (currentUser) { controls.push(new ComponentConnector(this, - 'topic-notifications-button', + 'topic-notifications-options', { + value: notificationLevel, topic, - appendReason: false, showFullTitle: false - } + }, + ["value"] )); } diff --git a/app/assets/javascripts/select-box-kit/components/admin-group-selector.js.es6 b/app/assets/javascripts/select-box-kit/components/admin-group-selector.js.es6 deleted file mode 100644 index 08248e72bda..00000000000 --- a/app/assets/javascripts/select-box-kit/components/admin-group-selector.js.es6 +++ /dev/null @@ -1,45 +0,0 @@ -import MultiComboBoxComponent from "select-box-kit/components/multi-combo-box"; - -export default MultiComboBoxComponent.extend({ - classNames: "admin-group-selector", - selected: null, - available: null, - allowAny: false, - - didReceiveAttrs() { - this._super(); - - this.set("value", this.get("selected").map(s => this._valueForContent(s))); - this.set("content", this.get("available")); - }, - - formatRowContent(content) { - let formatedContent = this._super(content); - formatedContent.locked = content.automatic; - return formatedContent; - }, - - didUpdateAttrs() { - this._super(); - - this.set("highlightedValue", null); - Ember.run.schedule("afterRender", () => { - this.autoHighlightFunction(); - }); - }, - - selectValuesFunction(values) { - values.forEach(value => { - this.triggerAction({ - action: "groupAdded", - actionContext: this.get("content").findBy("id", parseInt(value, 10)) - }); - }); - }, - - deselectValuesFunction(values) { - values.forEach(value => { - this.triggerAction({ action: "groupRemoved", actionContext: value }); - }); - } -}); diff --git a/app/assets/javascripts/select-box-kit/components/category-chooser.js.es6 b/app/assets/javascripts/select-box-kit/components/category-chooser.js.es6 deleted file mode 100644 index 668f168b38c..00000000000 --- a/app/assets/javascripts/select-box-kit/components/category-chooser.js.es6 +++ /dev/null @@ -1,131 +0,0 @@ -import ComboBoxComponent from "select-box-kit/components/combo-box"; -import { categoryBadgeHTML } from "discourse/helpers/category-link"; -import { on } from "ember-addons/ember-computed-decorators"; -import computed from "ember-addons/ember-computed-decorators"; -import PermissionType from "discourse/models/permission-type"; -import Category from "discourse/models/category"; -const { get, isNone, isEmpty } = Ember; - -export default ComboBoxComponent.extend({ - classNames: "category-chooser", - filterable: true, - castInteger: true, - allowUncategorized: null, - - filteredContentFunction(computedContent, computedValue, filter) { - if (isEmpty(filter)) { return computedContent; } - - const _matchFunction = (f, text) => { - return text.toLowerCase().indexOf(f) > -1; - }; - const lowerFilter = filter.toLowerCase(); - - return computedContent.filter(c => { - const category = Category.findById(get(c, "value")); - const text = get(c, "name"); - if (category && category.get("parentCategory")) { - const categoryName = category.get("parentCategory.name"); - return _matchFunction(lowerFilter, text) || _matchFunction(lowerFilter, categoryName); - } else { - return _matchFunction(lowerFilter, text); - } - }); - }, - - @computed("rootNone", "rootNoneLabel") - none(rootNone, rootNoneLabel) { - if (this.siteSettings.allow_uncategorized_topics || this.get("allowUncategorized")) { - if (!isNone(rootNone)) { - return rootNoneLabel || "category.none"; - } else { - return Category.findUncategorized(); - } - } else { - return "category.choose"; - } - }, - - @computed - templateForRow() { - return rowComponent => this._rowContentTemplate(rowComponent.get("content")); - }, - - @computed - templateForNoneRow() { - return rowComponent => this._rowContentTemplate(rowComponent.get("content")); - }, - - @computed("scopedCategoryId", "content.[]") - computedContent(scopedCategoryId, categories) { - // Always scope to the parent of a category, if present - if (scopedCategoryId) { - const scopedCat = Category.findById(scopedCategoryId); - scopedCategoryId = scopedCat.get("parent_category_id") || scopedCat.get("id"); - } - - const excludeCategoryId = this.get("excludeCategoryId"); - - return categories.filter(c => { - const categoryId = get(c, "value"); - if (scopedCategoryId && categoryId !== scopedCategoryId && get(c, "originalContent.parent_category_id") !== scopedCategoryId) { - return false; - } - if (get(c, 'originalContent.isUncategorizedCategory') || excludeCategoryId === categoryId) { - return false; - } - return get(c, 'originalContent.permission') === PermissionType.FULL; - }); - }, - - @on("didRender") - _bindComposerResizing() { - this.appEvents.on("composer:resized", this, this.applyDirection); - }, - - @on("willDestroyElement") - _unbindComposerResizing() { - this.appEvents.off("composer:resized"); - }, - - @computed("site.sortedCategories") - content() { - const categories = Discourse.SiteSettings.fixed_category_positions_on_create ? - Category.list() : - Category.listByActivity(); - return this.formatContents(categories); - }, - - _rowContentTemplate(content) { - let category; - - // If we have no id, but text with the uncategorized name, we can use that badge. - if (isEmpty(get(content, "value"))) { - const uncat = Category.findUncategorized(); - if (uncat && uncat.get("name") === get(content, "name")) { - category = uncat; - } - } else { - category = Category.findById(parseInt(get(content, "value"), 10)); - } - - if (!category) return get(content, "name"); - let result = categoryBadgeHTML(category, {link: false, allowUncategorized: true, hideParent: true}); - const parentCategoryId = category.get("parent_category_id"); - - if (parentCategoryId) { - result = `
${categoryBadgeHTML(Category.findById(parentCategoryId), {link: false})} ${result}`; - } else { - result = `
${result}`; - } - - result += ` × ${category.get("topic_count")}
`; - - const description = category.get("description"); - // TODO wtf how can this be null?; - if (description && description !== "null") { - result += `
${description.substr(0, 200)}${description.length > 200 ? '…' : ''}
`; - } - - return result; - } -}); diff --git a/app/assets/javascripts/select-box-kit/components/category-notifications-button.js.es6 b/app/assets/javascripts/select-box-kit/components/category-notifications-button.js.es6 deleted file mode 100644 index 05908840069..00000000000 --- a/app/assets/javascripts/select-box-kit/components/category-notifications-button.js.es6 +++ /dev/null @@ -1,13 +0,0 @@ -import NotificationOptionsComponent from "select-box-kit/components/notifications-button"; - -export default NotificationOptionsComponent.extend({ - classNames: "category-notifications-button", - isHidden: Ember.computed.or("category.deleted", "site.isMobileDevice"), - i18nPrefix: "category.notifications", - value: Ember.computed.alias("category.notification_level"), - headerComponent: "category-notifications-button/category-notifications-button-header", - - selectValueFunction(value) { - this.get("category").setNotification(value); - } -}); diff --git a/app/assets/javascripts/select-box-kit/components/category-notifications-button/category-notifications-button-header.js.es6 b/app/assets/javascripts/select-box-kit/components/category-notifications-button/category-notifications-button-header.js.es6 deleted file mode 100644 index 8c5ef82fe39..00000000000 --- a/app/assets/javascripts/select-box-kit/components/category-notifications-button/category-notifications-button-header.js.es6 +++ /dev/null @@ -1,13 +0,0 @@ -import NotificationButtonHeader from "select-box-kit/components/notifications-button/notifications-button-header"; -import computed from "ember-addons/ember-computed-decorators"; -import { iconHTML } from 'discourse-common/lib/icon-library'; - -export default NotificationButtonHeader.extend({ - classNames: "category-notifications-button-header", - shouldDisplaySelectedName: false, - - @computed("_selectedDetails.icon", "_selectedDetails.key") - icon() { - return `${this._super()}${iconHTML("caret-down")}`.htmlSafe(); - } -}); diff --git a/app/assets/javascripts/select-box-kit/components/combo-box/combo-box-header.js.es6 b/app/assets/javascripts/select-box-kit/components/combo-box/combo-box-header.js.es6 deleted file mode 100644 index 996ca1f4729..00000000000 --- a/app/assets/javascripts/select-box-kit/components/combo-box/combo-box-header.js.es6 +++ /dev/null @@ -1,39 +0,0 @@ -import SelectBoxKitHeaderComponent from "select-box-kit/components/select-box-kit/select-box-kit-header"; -import { default as computed } from "ember-addons/ember-computed-decorators"; - -export default SelectBoxKitHeaderComponent.extend({ - layoutName: "select-box-kit/templates/components/combo-box/combo-box-header", - classNames: "combo-box-header", - - clearable: Ember.computed.alias("options.clearable"), - caretUpIcon: Ember.computed.alias("options.caretUpIcon"), - caretDownIcon: Ember.computed.alias("options.caretDownIcon"), - selectedName: Ember.computed.alias("options.selectedName"), - - @computed("isExpanded", "caretUpIcon", "caretDownIcon") - caretIcon(isExpanded, caretUpIcon, caretDownIcon) { - return isExpanded === true ? caretUpIcon : caretDownIcon; - }, - - @computed("clearable", "selectedContent") - shouldDisplayClearableButton(clearable, selectedContent) { - return clearable === true && !Ember.isEmpty(selectedContent); - }, - - @computed("options.selectedName", "selectedContent.firstObject.name", "none.name") - selectedName(selectedName, name, noneName) { - if (Ember.isPresent(selectedName)) { - return selectedName; - } - - if (Ember.isNone(name)) { - if (Ember.isNone(noneName)) { - return this._super(); - } else { - return noneName; - } - } else { - return name; - } - } -}); diff --git a/app/assets/javascripts/select-box-kit/components/dropdown-select-box.js.es6 b/app/assets/javascripts/select-box-kit/components/dropdown-select-box.js.es6 deleted file mode 100644 index 10447655825..00000000000 --- a/app/assets/javascripts/select-box-kit/components/dropdown-select-box.js.es6 +++ /dev/null @@ -1,22 +0,0 @@ -import SelectBoxKitComponent from "select-box-kit/components/select-box-kit"; - -export default SelectBoxKitComponent.extend({ - classNames: "dropdown-select-box", - verticalOffset: 3, - fullWidthOnMobile: true, - filterable: false, - autoFilterable: false, - headerComponent: "dropdown-select-box/dropdown-select-box-header", - rowComponent: "dropdown-select-box/dropdown-select-box-row", - - clickOutside() { - if (this.get("isExpanded") === false) { return; } - this.close(); - }, - - didSelectValue() { - this._super(); - - this.blur(); - } -}); diff --git a/app/assets/javascripts/select-box-kit/components/dropdown-select-box/dropdown-select-box-header.js.es6 b/app/assets/javascripts/select-box-kit/components/dropdown-select-box/dropdown-select-box-header.js.es6 deleted file mode 100644 index 53dc082bdcc..00000000000 --- a/app/assets/javascripts/select-box-kit/components/dropdown-select-box/dropdown-select-box-header.js.es6 +++ /dev/null @@ -1,6 +0,0 @@ -import SelectBoxKitHeaderComponent from "select-box-kit/components/select-box-kit/select-box-kit-header"; - -export default SelectBoxKitHeaderComponent.extend({ - layoutName: "select-box-kit/templates/components/dropdown-select-box/dropdown-select-box-header", - classNames: "dropdown-select-box-header", -}); diff --git a/app/assets/javascripts/select-box-kit/components/dropdown-select-box/dropdown-select-box-row.js.es6 b/app/assets/javascripts/select-box-kit/components/dropdown-select-box/dropdown-select-box-row.js.es6 deleted file mode 100644 index 38ce2a7aa03..00000000000 --- a/app/assets/javascripts/select-box-kit/components/dropdown-select-box/dropdown-select-box-row.js.es6 +++ /dev/null @@ -1,9 +0,0 @@ -import SelectBoxKitRowComponent from "select-box-kit/components/select-box-kit/select-box-kit-row"; - -export default SelectBoxKitRowComponent.extend({ - layoutName: "select-box-kit/templates/components/dropdown-select-box/dropdown-select-box-row", - classNames: "dropdown-select-box-row", - - name: Ember.computed.alias("content.name"), - description: Ember.computed.alias("content.originalContent.description") -}); diff --git a/app/assets/javascripts/select-box-kit/components/future-date-input-selector/future-date-input-selector-header.js.es6 b/app/assets/javascripts/select-box-kit/components/future-date-input-selector/future-date-input-selector-header.js.es6 deleted file mode 100644 index e62e1276251..00000000000 --- a/app/assets/javascripts/select-box-kit/components/future-date-input-selector/future-date-input-selector-header.js.es6 +++ /dev/null @@ -1,14 +0,0 @@ -import ComboBoxHeaderComponent from "select-box-kit/components/combo-box/combo-box-header"; -import DatetimeMixin from "select-box-kit/components/future-date-input-selector/mixin"; -import computed from "ember-addons/ember-computed-decorators"; - -export default ComboBoxHeaderComponent.extend(DatetimeMixin, { - layoutName: "select-box-kit/templates/components/future-date-input-selector/future-date-input-selector-header", - classNames: "future-date-input-selector-header", - - @computed("selectedContent.firstObject.value") - datetime(value) { return this._computeDatetimeForValue(value); }, - - @computed("selectedContent.firstObject.value") - icon(value) { return this._computeIconForValue(value); } -}); diff --git a/app/assets/javascripts/select-box-kit/components/future-date-input-selector/future-date-input-selector-row.js.es6 b/app/assets/javascripts/select-box-kit/components/future-date-input-selector/future-date-input-selector-row.js.es6 deleted file mode 100644 index be35212a761..00000000000 --- a/app/assets/javascripts/select-box-kit/components/future-date-input-selector/future-date-input-selector-row.js.es6 +++ /dev/null @@ -1,14 +0,0 @@ -import SelectBoxKitRowComponent from "select-box-kit/components/select-box-kit/select-box-kit-row"; -import DatetimeMixin from "select-box-kit/components/future-date-input-selector/mixin"; -import computed from "ember-addons/ember-computed-decorators"; - -export default SelectBoxKitRowComponent.extend(DatetimeMixin, { - layoutName: "select-box-kit/templates/components/future-date-input-selector/future-date-input-selector-row", - classNames: "future-date-input-selector-row", - - @computed("content.value") - datetime(value) { return this._computeDatetimeForValue(value); }, - - @computed("content.value") - icon(value) { return this._computeIconForValue(value); } -}); diff --git a/app/assets/javascripts/select-box-kit/components/list-setting.js.es6 b/app/assets/javascripts/select-box-kit/components/list-setting.js.es6 deleted file mode 100644 index 94fa2fa66f2..00000000000 --- a/app/assets/javascripts/select-box-kit/components/list-setting.js.es6 +++ /dev/null @@ -1,55 +0,0 @@ -import MultiComboBoxComponent from "select-box-kit/components/multi-combo-box"; -import { observes } from 'ember-addons/ember-computed-decorators'; - -export default MultiComboBoxComponent.extend({ - classNames: "list-setting", - tokenSeparator: "|", - settingValue: "", - choices: null, - filterable: true, - - init() { - const valuesFromString = this.get("settingValue").split(this.get("tokenSeparator")); - this.set("value", valuesFromString.reject(v => Ember.isEmpty(v))); - - if (Ember.isNone(this.get("choices"))) { - this.set("content", valuesFromString); - } else { - this.set("content", this.get("choices")); - } - - if (!Ember.isNone(this.get("settingName"))) { - this.set("nameProperty", this.get("settingName")); - } - - if (Ember.isEmpty(this.get("content"))) { - this.set("rowComponent", null); - this.set("noContentLabel", null); - } - - this._super(); - - if (this.get("nameProperty").indexOf("color") > -1) { - this.set("headerComponentOptions", Ember.Object.create({ - selectedNameComponent: "multi-combo-box/selected-color" - })); - } - }, - - @observes("value.[]") - setSettingValue() { - this.set("settingValue", this.get("value").join(this.get("tokenSeparator"))); - }, - - @observes("content.[]") - setChoices() { this.set("choices", this.get("content")); }, - - _handleTabOnKeyDown(event) { - if (this.$highlightedRow().length === 1) { - this._super(event); - } else { - this.close(); - return false; - } - } -}); diff --git a/app/assets/javascripts/select-box-kit/components/multi-combo-box.js.es6 b/app/assets/javascripts/select-box-kit/components/multi-combo-box.js.es6 deleted file mode 100644 index bf08d7da1f1..00000000000 --- a/app/assets/javascripts/select-box-kit/components/multi-combo-box.js.es6 +++ /dev/null @@ -1,240 +0,0 @@ -import SelectBoxKitComponent from "select-box-kit/components/select-box-kit"; -import computed from "ember-addons/ember-computed-decorators"; -const { get, isNone, isEmpty } = Ember; - -export default SelectBoxKitComponent.extend({ - classNames: "multi-combo-box", - headerComponent: "multi-combo-box/multi-combo-box-header", - filterComponent: null, - headerText: "select_box.default_header_text", - allowAny: true, - allowValueMutation: false, - autoSelectFirst: false, - autoFilterable: true, - selectedNameComponent: "multi-combo-box/selected-name", - - init() { - this._super(); - - if (isNone(this.get("value"))) { this.set("value", []); } - - this.set("headerComponentOptions", Ember.Object.create({ - selectedNameComponent: this.get("selectedNameComponent") - })); - }, - - @computed("filter") - templateForCreateRow() { - return (rowComponent) => { - return I18n.t("select_box.create", { content: rowComponent.get("content.name")}); - }; - }, - - keyDown(event) { - const keyCode = event.keyCode || event.which; - const $filterInput = this.$filterInput(); - - if (this.get("isFocused") === true && this.get("isExpanded") === false && keyCode === this.keys.BACKSPACE) { - this.expand(); - return; - } - - // select all choices - if (event.metaKey === true && keyCode === 65 && isEmpty(this.get("filter"))) { - this.$(".choices .selected-name:not(.is-locked)").addClass("is-highlighted"); - return; - } - - // clear selection when multiple - if (Ember.isEmpty(this.get("filter")) && this.$(".selected-name.is-highlighted").length >= 1 && keyCode === this.keys.BACKSPACE) { - const highlightedValues = []; - $.each(this.$(".selected-name.is-highlighted"), (i, el) => { - highlightedValues.push($(el).attr("data-value")); - }); - - this.send("onDeselect", highlightedValues); - return; - } - - // try to remove last item from the list - if (Ember.isEmpty(this.get("filter")) && keyCode === this.keys.BACKSPACE) { - let $lastSelectedValue = $(this.$(".choices .selected-name:not(.is-locked)").last()); - - if ($lastSelectedValue.length === 0) { return; } - - if ($lastSelectedValue.hasClass("is-highlighted") || $(document.activeElement).is($lastSelectedValue)) { - this.send("onDeselect", this.get("selectedContent.lastObject.value")); - $filterInput.focus(); - return; - } - - if ($filterInput.not(":visible") && $lastSelectedValue.length > 0) { - $lastSelectedValue.click(); - return false; - } - - if ($filterInput.val() === "") { - if ($filterInput.is(":focus")) { - if ($lastSelectedValue.length > 0) { $lastSelectedValue.click(); } - } else { - if ($lastSelectedValue.length > 0) { - $lastSelectedValue.click(); - } else { - $filterInput.focus(); - } - } - } - } - }, - - @computed("value.[]") - computedValue(value) { return value.map(v => this._castInteger(v)); }, - - @computed("value.[]", "computedContent.[]") - selectedContent(value, computedContent) { - const contents = []; - value.forEach(v => { - const content = computedContent.findBy("value", v); - if (!isNone(content)) { contents.push(content); } - }); - return contents; - }, - - filteredContentFunction(computedContent, computedValue, filter) { - computedContent = computedContent.filter(c => { - return !computedValue.includes(get(c, "value")); - }); - - if (isEmpty(filter)) { return computedContent; } - - const lowerFilter = filter.toLowerCase(); - return computedContent.filter(c => { - return get(c, "name").toLowerCase().indexOf(lowerFilter) > -1; - }); - }, - - willCreateContent() { - this.set("highlightedValue", null); - }, - - didCreateContent() { - this.clearFilter(); - this.autoHighlightFunction(); - }, - - createContentFunction(input) { - if (!this.get("content").includes(input)) { - this.get("content").pushObject(input); - this.get("value").pushObject(input); - } - }, - - deselectValuesFunction(values) { - const contents = this._computeRemovableContentsForValues(values); - this.get("value").removeObjects(values); - this.get("content").removeObjects(contents); - }, - - highlightValueFunction(value) { - this.set("highlightedValue", value); - }, - - selectValuesFunction(values) { - this.get("value").pushObjects(values); - }, - - willSelectValues() { - this.expand(); - this.set("highlightedValue", null); - }, - - didSelectValues() { - this.focus(); - this.clearFilter(); - this.autoHighlightFunction(); - }, - - willDeselectValues() { - this.set("highlightedValue", null); - }, - - didDeselectValues() { - this.autoHighlightFunction(); - }, - - willHighlightValue() {}, - - didHighlightValue() {}, - - autoHighlightFunction() { - Ember.run.schedule("afterRender", () => { - if (this.get("isExpanded") === false) { return; } - if (this.get("renderedBodyOnce") === false) { return; } - if (!isNone(this.get("highlightedValue"))) { return; } - - if (isEmpty(this.get("filteredContent"))) { - if (!isEmpty(this.get("filter"))) { - this.send("onHighlight", this.get("filter")); - } else if (this.get("none") && !isEmpty(this.get("selectedContent"))) { - this.send("onHighlight", this.noneValue); - } - } else { - this.send("onHighlight", this.get("filteredContent.firstObject.value")); - } - }); - }, - - actions: { - onClearSelection() { - const values = this.get("selectedContent").map(c => get(c, "value")); - this.send("onDeselect", values); - }, - - onHighlight(value) { - value = this._originalValueForValue(value); - this.willHighlightValue(value); - this.set("highlightedValue", value); - this.highlightValueFunction(value); - this.didHighlightValue(value); - }, - - onCreateContent(input) { - this.willCreateContent(input); - this.createContentFunction(input); - this.didCreateContent(input); - }, - - onSelect(values) { - values = Ember.makeArray(values).map(v => this._originalValueForValue(v)); - this.willSelectValues(values); - this.selectValuesFunction(values); - this.didSelectValues(values); - }, - - onDeselect(values) { - values = Ember.makeArray(this._computeRemovableValues(values)); - this.willDeselectValues(values); - this.deselectValuesFunction(values); - this.didSelectValues(values); - } - }, - - _computeRemovableContentsForValues(values) { - const removableContents = []; - values.forEach(v => { - if (!this.get("_initialValues").includes(v)) { - const content = this._contentForValue(v); - if (!isNone(content)) { removableContents.push(content); } - } - }); - return removableContents; - }, - - _computeRemovableValues(values) { - return Ember.makeArray(values) - .map(v => this._originalValueForValue(v)) - .filter(v => { - return get(this._computedContentForValue(v), "locked") !== true; - }); - } -}); diff --git a/app/assets/javascripts/select-box-kit/components/multi-combo-box/selected-color.js.es6 b/app/assets/javascripts/select-box-kit/components/multi-combo-box/selected-color.js.es6 deleted file mode 100644 index 240c3570d9e..00000000000 --- a/app/assets/javascripts/select-box-kit/components/multi-combo-box/selected-color.js.es6 +++ /dev/null @@ -1,8 +0,0 @@ -import SelectedNameComponent from "select-box-kit/components/multi-combo-box/selected-name"; - -export default SelectedNameComponent.extend({ - didRender() { - const name = this.get("content.name"); - this.$().css("border-bottom", Handlebars.Utils.escapeExpression(`7px solid #${name}`)); - } -}); diff --git a/app/assets/javascripts/select-box-kit/components/notifications-button/notifications-button-header.js.es6 b/app/assets/javascripts/select-box-kit/components/notifications-button/notifications-button-header.js.es6 deleted file mode 100644 index 268e8d7b311..00000000000 --- a/app/assets/javascripts/select-box-kit/components/notifications-button/notifications-button-header.js.es6 +++ /dev/null @@ -1,26 +0,0 @@ -import DropdownSelectBoxHeaderComponent from "select-box-kit/components/dropdown-select-box/dropdown-select-box-header"; -import computed from "ember-addons/ember-computed-decorators"; -import { iconHTML } from 'discourse-common/lib/icon-library'; -import { buttonDetails } from "discourse/lib/notification-levels"; - -export default DropdownSelectBoxHeaderComponent.extend({ - classNames: "notifications-button-header", - - i18nPrefix: Ember.computed.alias("options.i18nPrefix"), - shouldDisplaySelectedName: Ember.computed.alias("options.showFullTitle"), - - @computed("_selectedDetails.icon", "_selectedDetails.key") - icon(icon, key) { - return iconHTML(icon, { class: key }).htmlSafe(); - }, - - @computed("_selectedDetails.key", "i18nPrefix") - selectedName(key, prefix) { - return I18n.t(`${prefix}.${key}.title`); - }, - - @computed("selectedContent.firstObject.value") - _selectedDetails(value) { - return buttonDetails(value); - } -}); diff --git a/app/assets/javascripts/select-box-kit/components/pinned-options.js.es6 b/app/assets/javascripts/select-box-kit/components/pinned-options.js.es6 deleted file mode 100644 index 3c96f2ee228..00000000000 --- a/app/assets/javascripts/select-box-kit/components/pinned-options.js.es6 +++ /dev/null @@ -1,60 +0,0 @@ -import DropdownSelectBoxComponent from "select-box-kit/components/dropdown-select-box"; -import computed from "ember-addons/ember-computed-decorators"; -import { observes } from "ember-addons/ember-computed-decorators"; -import { on } from "ember-addons/ember-computed-decorators"; - -export default DropdownSelectBoxComponent.extend({ - classNames: "pinned-options", - - headerComponent: "pinned-options/pinned-options-header", - - @on("didReceiveAttrs") - _setComponentOptions() { - this.set("headerComponentOptions", Ember.Object.create({ - pinned: this.get("topic.pinned"), - pinnedGlobally: this.get("topic.pinned_globally") - })); - }, - - @computed("topic.pinned") - value(pinned) { - return pinned ? "pinned" : "unpinned"; - }, - - @observes("topic.pinned") - _pinStateChanged() { - this.set("value", this.get("topic.pinned") ? "pinned" : "unpinned"); - this._setComponentOptions(); - }, - - @computed("topic.pinned_globally") - content(pinnedGlobally) { - const globally = pinnedGlobally ? "_globally" : ""; - - return [ - { - id: "pinned", - name: I18n.t("topic_statuses.pinned" + globally + ".title"), - description: I18n.t('topic_statuses.pinned' + globally + '.help'), - icon: "thumb-tack" - }, - { - id: "unpinned", - name: I18n.t("topic_statuses.unpinned.title"), - icon: "thumb-tack", - description: I18n.t('topic_statuses.unpinned.help'), - iconClass: "unpinned" - } - ]; - }, - - selectValueFunction(value) { - const topic = this.get("topic"); - - if (value === "unpinned") { - topic.clearPin(); - } else { - topic.rePin(); - } - } -}); diff --git a/app/assets/javascripts/select-box-kit/components/pinned-options/pinned-options-header.js.es6 b/app/assets/javascripts/select-box-kit/components/pinned-options/pinned-options-header.js.es6 deleted file mode 100644 index 3f83e8bffda..00000000000 --- a/app/assets/javascripts/select-box-kit/components/pinned-options/pinned-options-header.js.es6 +++ /dev/null @@ -1,30 +0,0 @@ -import DropdownSelectBoxHeaderComponent from "select-box-kit/components/dropdown-select-box/dropdown-select-box-header"; -import computed from "ember-addons/ember-computed-decorators"; -import { iconHTML } from 'discourse-common/lib/icon-library'; - -export default DropdownSelectBoxHeaderComponent.extend({ - classNames: "pinned-options-header", - - pinnedGlobally: Ember.computed.alias("options.pinnedGlobally"), - pinned: Ember.computed.alias("options.pinned"), - - @computed("pinned", "pinnedGlobally") - icon(pinned, pinnedGlobally) { - const globally = pinnedGlobally ? "_globally" : ""; - const state = pinned ? `pinned${globally}` : "unpinned"; - - return iconHTML( - "thumb-tack", - { class: (state === "unpinned" ? "unpinned" : null) } - ); - }, - - @computed("pinned", "pinnedGlobally") - selectedName(pinned, pinnedGlobally) { - const globally = pinnedGlobally ? "_globally" : ""; - const state = pinned ? `pinned${globally}` : "unpinned"; - const title = I18n.t(`topic_statuses.${state}.title`); - - return `${title}${iconHTML("caret-down")}`.htmlSafe(); - }, -}); diff --git a/app/assets/javascripts/select-box-kit/components/select-box-kit.js.es6 b/app/assets/javascripts/select-box-kit/components/select-box-kit.js.es6 deleted file mode 100644 index a3371d0249c..00000000000 --- a/app/assets/javascripts/select-box-kit/components/select-box-kit.js.es6 +++ /dev/null @@ -1,328 +0,0 @@ -const { get, isNone, isEmpty, isPresent } = Ember; -import { on } from "ember-addons/ember-computed-decorators"; -import computed from "ember-addons/ember-computed-decorators"; -import UtilsMixin from "select-box-kit/mixins/utils"; -import DomHelpersMixin from "select-box-kit/mixins/dom-helpers"; -import KeyboardMixin from "select-box-kit/mixins/keyboard"; - -export default Ember.Component.extend(UtilsMixin, DomHelpersMixin, KeyboardMixin, { - layoutName: "select-box-kit/templates/components/select-box-kit", - classNames: "select-box-kit", - classNameBindings: [ - "isFocused", - "isExpanded", - "isDisabled", - "isHidden", - "isAbove", - "isBelow", - "isLeftAligned", - "isRightAligned" - ], - isDisabled: false, - isExpanded: false, - isFocused: false, - isHidden: false, - renderedBodyOnce: false, - renderedFilterOnce: false, - tabindex: 0, - scrollableParentSelector: ".modal-body", - value: null, - none: null, - highlightedValue: null, - noContentLabel: "select_box.no_content", - valueAttribute: "id", - nameProperty: "name", - autoFilterable: false, - filterable: false, - filter: "", - filterPlaceholder: "select_box.filter_placeholder", - filterIcon: "search", - rowComponent: "select-box-kit/select-box-kit-row", - rowComponentOptions: null, - noneRowComponent: "select-box-kit/select-box-kit-none-row", - createRowComponent: "select-box-kit/select-box-kit-create-row", - filterComponent: "select-box-kit/select-box-kit-filter", - headerComponent: "select-box-kit/select-box-kit-header", - headerComponentOptions: null, - collectionComponent: "select-box-kit/select-box-kit-collection", - collectionHeight: 200, - verticalOffset: 0, - horizontalOffset: 0, - fullWidthOnMobile: false, - castInteger: false, - allowAny: false, - allowValueMutation: true, - autoSelectFirst: true, - content: null, - _initialValues: null, - - init() { - this._super(); - - this.noneValue = "__none__"; - this._previousScrollParentOverflow = "auto"; - this._previousCSSContext = {}; - this.set("headerComponentOptions", Ember.Object.create()); - this.set("rowComponentOptions", Ember.Object.create()); - - if ($(window).outerWidth(false) <= 420) { - this.setProperties({ filterable: false, autoFilterable: false }); - } - - if (isNone(this.get("content"))) { this.set("content", []); } - this.set("value", this._castInteger(this.get("value"))); - - this.setInitialValues(); - }, - - setInitialValues() { - this.set("_initialValues", this.getWithDefault("content", []).map((c) => { - return this._valueForContent(c); - })); - }, - - @computed("computedContent.[]", "computedValue.[]", "filter") - filteredContent(computedContent, computedValue, filter) { - return this.filteredContentFunction(computedContent, computedValue, filter); - }, - - filteredContentFunction(computedContent, computedValue, filter) { - if (isEmpty(filter)) { return computedContent; } - - const lowerFilter = filter.toLowerCase(); - return computedContent.filter(c => { - return get(c, "name").toLowerCase().indexOf(lowerFilter) > -1; - }); - }, - - formatRowContent(content) { - let originalContent; - - if (typeof content === "string" || typeof content === "number") { - originalContent = {}; - originalContent[this.get("valueAttribute")] = content; - originalContent[this.get("nameProperty")] = content; - } else { - originalContent = content; - } - - return { - value: this._castInteger(this._valueForContent(content)), - name: this._nameForContent(content), - locked: false, - originalContent - }; - }, - - formatContents(contents) { - return contents.map(content => this.formatRowContent(content)); - }, - - @computed("filter", "filterable", "autoFilterable", "renderedFilterOnce") - shouldDisplayFilter(filter, filterable, autoFilterable, renderedFilterOnce) { - if (renderedFilterOnce === true || filterable === true) { return true; } - if (filter.length > 0 && autoFilterable === true) { return true; } - return false; - }, - - @computed("filter") - shouldDisplayCreateRow(filter) { - if (this.get("allowAny") === true && filter.length > 0) { return true; } - return false; - }, - - @computed("filter", "shouldDisplayCreateRow") - createRowContent(filter, shouldDisplayCreateRow) { - if (shouldDisplayCreateRow === true && !this.get("value").includes(filter)) { - return Ember.Object.create({ value: filter, name: filter }); - } - }, - - @computed("content.[]", "value.[]") - computedContent(content) { - this._mutateValue(); - return this.formatContents(content || []); - }, - - @computed("value", "none", "computedContent.firstObject.value") - computedValue(value, none, firstContentValue) { - if (isNone(value) && isNone(none) && this.get("autoSelectFirst") === true) { - return firstContentValue; - } - - return value; - }, - - @computed - templateForRow() { return () => null; }, - - @computed - templateForNoneRow() { return () => null; }, - - @computed - templateForCreateRow() { return () => null; }, - - @computed("none") - computedNone(none) { - if (isNone(none)) { return null; } - - switch (typeof none) { - case "string": - return Ember.Object.create({ name: I18n.t(none), value: this.noneValue }); - default: - return this.formatRowContent(none); - } - }, - - @computed("computedValue", "computedContent.[]") - selectedContent(computedValue, computedContent) { - if (isNone(computedValue)) { return []; } - return [ computedContent.findBy("value", computedValue) ]; - }, - - @on("didInsertElement") - _setupResizeListener() { - $(window).on("resize.select-box-kit", () => this.collapse() ); - }, - - - autoHighlightFunction() { - Ember.run.schedule("afterRender", () => { - if (!isNone(this.get("highlightedValue"))) { return; } - - const filteredContent = this.get("filteredContent"); - const display = this.get("shouldDisplayCreateRow"); - const none = this.get("computedNone"); - - if (isNone(this.get("highlightedValue")) && !isEmpty(filteredContent)) { - this.send("onHighlight", get(filteredContent, "firstObject.value")); - return; - } - - if (display === true && isEmpty(filteredContent)) { - this.send("onHighlight", this.get("filter")); - } - else if (!isEmpty(filteredContent)) { - this.send("onHighlight", get(filteredContent, "firstObject.value")); - } - else if (isEmpty(filteredContent) && isPresent(none) && display === false) { - this.send("onHighlight", get(none, "value")); - } - }); - }, - - willFilterContent() { - this.expand(); - this.set("highlightedValue", null); - }, - didFilterContent() { - this.set("renderedFilterOnce", true); - this.autoHighlightFunction(); - }, - - willCreateContent() { }, - createContentFunction(input) { - this.get("content").pushObject(input); - this.send("onSelect", input); - }, - didCreateContent() { - this.clearFilter(); - this.autoHighlightFunction(); - }, - - willHighlightValue() {}, - highlightValueFunction(value) { - this.set("highlightedValue", value); - }, - didHighlightValue() {}, - - willSelectValue() { - this.clearFilter(); - this.set("highlightedValue", null); - }, - selectValueFunction(value) { - this.set("value", value); - }, - didSelectValue() { - this.collapse(); - this.focus(); - }, - - willDeselectValue() { - this.set("highlightedValue", null); - }, - unsetValueFunction() { - this.set("value", null); - }, - didDeselectValue() { - this.focus(); - }, - - actions: { - onToggle() { - this.get("isExpanded") === true ? this.collapse() : this.expand(); - }, - - onClearSelection() { - this.send("onDeselect", this.get("value")); - }, - - onHighlight(value) { - value = this._originalValueForValue(value); - this.willHighlightValue(value); - this.set("highlightedValue", value); - this.highlightValueFunction(value); - this.didHighlightValue(value); - }, - - onCreateContent(input) { - this.willCreateContent(input); - this.createContentFunction(input); - this.didCreateContent(input); - }, - - onSelect(value) { - if (value === "") { value = null; } - this.willSelectValue(value); - this.selectValueFunction(value); - this.didSelectValue(value); - }, - - onDeselect(value) { - value = this._originalValueForValue(value); - this.willDeselectValue(value); - this.unsetValueFunction(value); - this.didSelectValue(value); - }, - - onFilterChange(_filter) { - this.willFilterContent(_filter); - this.set("filter", _filter); - this.didFilterContent(_filter); - }, - }, - - clearFilter() { - this.$filterInput().val(""); - this.setProperties({ filter: "" }); - }, - - @on("didReceiveAttrs") - _mutateValue() { - if (this.get("allowValueMutation") !== true) { - return; - } - - const none = isNone(this.get("none")); - const emptyValue = isEmpty(this.get("value")); - - if (none && emptyValue) { - Ember.run.scheduleOnce("sync", () => { - if (!isEmpty(this.get("computedContent"))) { - const firstValue = this.get("computedContent.firstObject.value"); - this.set("value", firstValue); - } - }); - } - } -}); diff --git a/app/assets/javascripts/select-box-kit/components/select-box-kit/select-box-kit-collection.js.es6 b/app/assets/javascripts/select-box-kit/components/select-box-kit/select-box-kit-collection.js.es6 deleted file mode 100644 index ca378f5ef93..00000000000 --- a/app/assets/javascripts/select-box-kit/components/select-box-kit/select-box-kit-collection.js.es6 +++ /dev/null @@ -1,5 +0,0 @@ -export default Ember.Component.extend({ - layoutName: "select-box-kit/templates/components/select-box-kit/select-box-kit-collection", - classNames: "select-box-kit-collection", - tagName: "ul" -}); diff --git a/app/assets/javascripts/select-box-kit/components/select-box-kit/select-box-kit-create-row.js.es6 b/app/assets/javascripts/select-box-kit/components/select-box-kit/select-box-kit-create-row.js.es6 deleted file mode 100644 index fd686080ec9..00000000000 --- a/app/assets/javascripts/select-box-kit/components/select-box-kit/select-box-kit-create-row.js.es6 +++ /dev/null @@ -1,10 +0,0 @@ -import SelectBoxKitRowComponent from "select-box-kit/components/select-box-kit/select-box-kit-row"; - -export default SelectBoxKitRowComponent.extend({ - layoutName: "select-box-kit/templates/components/select-box-kit/select-box-kit-row", - classNames: "create", - - click() { - this.sendAction("onCreateContent", this.get("content.name")); - }, -}); diff --git a/app/assets/javascripts/select-box-kit/components/select-box-kit/select-box-kit-header.js.es6 b/app/assets/javascripts/select-box-kit/components/select-box-kit/select-box-kit-header.js.es6 deleted file mode 100644 index b7797571ae3..00000000000 --- a/app/assets/javascripts/select-box-kit/components/select-box-kit/select-box-kit-header.js.es6 +++ /dev/null @@ -1,28 +0,0 @@ -import computed from 'ember-addons/ember-computed-decorators'; - -export default Ember.Component.extend({ - layoutName: "select-box-kit/templates/components/select-box-kit/select-box-kit-header", - classNames: "select-box-kit-header", - classNameBindings: ["isFocused"], - attributeBindings: ["selectedName:data-name"], - shouldDisplaySelectedName: true, - - @computed("options.shouldDisplaySelectedName") - shouldDisplaySelectedName(should) { - if (Ember.isNone(should)) { return true; } - return should; - }, - - @computed("options.selectedName", "selectedContent.firstObject.name") - selectedName(optionsSelectedName, firstSelectedContentName) { - if (Ember.isNone(optionsSelectedName)) { - return firstSelectedContentName; - } - return optionsSelectedName; - }, - - @computed("options.icon") - icon(optionsIcon) { return optionsIcon; }, - - click() { this.sendAction("onToggle"); } -}); diff --git a/app/assets/javascripts/select-box-kit/components/select-box-kit/select-box-kit-none-row.js.es6 b/app/assets/javascripts/select-box-kit/components/select-box-kit/select-box-kit-none-row.js.es6 deleted file mode 100644 index fbc07b312c6..00000000000 --- a/app/assets/javascripts/select-box-kit/components/select-box-kit/select-box-kit-none-row.js.es6 +++ /dev/null @@ -1,10 +0,0 @@ -import SelectBoxKitRowComponent from "select-box-kit/components/select-box-kit/select-box-kit-row"; - -export default SelectBoxKitRowComponent.extend({ - layoutName: "select-box-kit/templates/components/select-box-kit/select-box-kit-row", - classNames: "none", - - click() { - this.sendAction("onClearSelection"); - } -}); diff --git a/app/assets/javascripts/select-box-kit/components/select-box-kit/select-box-kit-row.js.es6 b/app/assets/javascripts/select-box-kit/components/select-box-kit/select-box-kit-row.js.es6 deleted file mode 100644 index c1bf0f2d5ed..00000000000 --- a/app/assets/javascripts/select-box-kit/components/select-box-kit/select-box-kit-row.js.es6 +++ /dev/null @@ -1,70 +0,0 @@ -import { iconHTML } from 'discourse-common/lib/icon-library'; -import { on } from 'ember-addons/ember-computed-decorators'; -import computed from 'ember-addons/ember-computed-decorators'; -const { run, isPresent } = Ember; -import UtilsMixin from "select-box-kit/mixins/utils"; - -export default Ember.Component.extend(UtilsMixin, { - layoutName: "select-box-kit/templates/components/select-box-kit/select-box-kit-row", - classNames: "select-box-kit-row", - tagName: "li", - tabIndex: -1, - attributeBindings: [ - "tabIndex", - "title", - "content.value:data-value", - "content.name:data-name" - ], - classNameBindings: ["isHighlighted", "isSelected"], - clicked: false, - - @computed("content.originalContent.title", "content.name") - title(title, name) { - return title || name; - }, - - @computed("templateForRow") - template(templateForRow) { return templateForRow(this); }, - - @on("didReceiveAttrs") - _setSelectionState() { - const contentValue = this.get("content.value"); - - this.set("isSelected", this.get("value") === contentValue); - this.set("isHighlighted", this.get("highlightedValue") === contentValue); - }, - - @on("willDestroyElement") - _clearDebounce() { - const hoverDebounce = this.get("hoverDebounce"); - if (isPresent(hoverDebounce)) { run.cancel(hoverDebounce); } - }, - - @computed("content.originalContent.icon", "content.originalContent.iconClass") - icon(icon, cssClass) { - if (icon) { - return iconHTML(icon, { class: cssClass }); - } - - return null; - }, - - mouseEnter() { - this.set("hoverDebounce", run.debounce(this, this._sendOnHighlightAction, 32)); - }, - - click() { - this._sendOnSelectAction(); - }, - - _sendOnSelectAction() { - if (this.get("clicked") === false) { - this.set("clicked", true); - this.sendAction("onSelect", this.get("content.value")); - } - }, - - _sendOnHighlightAction() { - this.sendAction("onHighlight", this.get("content.value")); - } -}); diff --git a/app/assets/javascripts/select-box-kit/components/tag-notifications-button.js.es6 b/app/assets/javascripts/select-box-kit/components/tag-notifications-button.js.es6 deleted file mode 100644 index bc2d95ac4d0..00000000000 --- a/app/assets/javascripts/select-box-kit/components/tag-notifications-button.js.es6 +++ /dev/null @@ -1,12 +0,0 @@ -import NotificationOptionsComponent from "select-box-kit/components/notifications-button"; - -export default NotificationOptionsComponent.extend({ - classNames: "tag-notifications-button", - i18nPrefix: "tagging.notifications", - showFullTitle: false, - headerComponent: "tag-notifications-button/tag-notifications-button-header", - - selectValueFunction(value) { - this.sendAction("action", value); - } -}); diff --git a/app/assets/javascripts/select-box-kit/components/tag-notifications-button/tag-notifications-button-header.js.es6 b/app/assets/javascripts/select-box-kit/components/tag-notifications-button/tag-notifications-button-header.js.es6 deleted file mode 100644 index 524c8b8585d..00000000000 --- a/app/assets/javascripts/select-box-kit/components/tag-notifications-button/tag-notifications-button-header.js.es6 +++ /dev/null @@ -1,13 +0,0 @@ -import NotificationButtonHeader from "select-box-kit/components/notifications-button/notifications-button-header"; -import computed from "ember-addons/ember-computed-decorators"; -import { iconHTML } from 'discourse-common/lib/icon-library'; - -export default NotificationButtonHeader.extend({ - classNames: "tag-notifications-button-header", - shouldDisplaySelectedName: false, - - @computed("_selectedDetails.icon", "_selectedDetails.key") - icon() { - return `${this._super()}${iconHTML("caret-down")}`.htmlSafe(); - } -}); diff --git a/app/assets/javascripts/select-box-kit/mixins/keyboard.js.es6 b/app/assets/javascripts/select-box-kit/mixins/keyboard.js.es6 deleted file mode 100644 index e7973f5b0f8..00000000000 --- a/app/assets/javascripts/select-box-kit/mixins/keyboard.js.es6 +++ /dev/null @@ -1,222 +0,0 @@ -export default Ember.Mixin.create({ - init() { - this._super(); - - this.keys = { - 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 - }; - }, - - willDestroyElement() { - this._super(); - - $(document) - .off("mousedown.select-box-kit") - .off("touchstart.select-box-kit"); - - this.$offscreenInput() - .off("focus.select-box-kit") - .off("focusin.select-box-kit") - .off("blur.select-box-kit") - .off("keypress.select-box-kit") - .off("keydown.select-box-kit"); - - this.$filterInput() - .off("change.select-box-kit") - .off("keypress.select-box-kit") - .off("keydown.select-box-kit"); - }, - - didInsertElement() { - this._super(); - - $(document) - .on("mousedown.select-box-kit, touchstart.select-box-kit", event => { - if (Ember.isNone(this.get("element"))) { - return; - } - - if (this.get("element").contains(event.target)) { return; } - this.clickOutside(event); - }); - - this.$offscreenInput() - .on("blur.select-box-kit", () => { - if (this.get("isExpanded") === false && this.get("isFocused") === true) { - this.close(); - } - }) - .on("focus.select-box-kit", (event) => { - this.set("isFocused", true); - this._killEvent(event); - }) - .on("focusin.select-box-kit", (event) => { - this.set("isFocused", true); - this._killEvent(event); - }) - .on("keydown.select-box-kit", (event) => { - const keyCode = event.keyCode || event.which; - - if (keyCode === this.keys.TAB) { this._handleTabOnKeyDown(event); } - if (keyCode === this.keys.ESC) { this._handleEscOnKeyDown(event); } - if (keyCode === this.keys.UP || keyCode === this.keys.DOWN) { - this._handleArrowKey(keyCode, event); - } - if (keyCode === this.keys.BACKSPACE) { - this.expand(); - - if (this.$filterInput().is(":visible")) { - this.$filterInput().focus().trigger(event).trigger("change"); - } - - return event; - } - - return true; - }) - .on("keypress.select-box-kit", (event) => { - const keyCode = event.keyCode || event.which; - - switch (keyCode) { - case this.keys.ENTER: - if (this.get("isExpanded") === false) { - this.expand(); - } else if (this.$highlightedRow().length === 1) { - this.$highlightedRow().click(); - } - return false; - case this.keys.BACKSPACE: - return event; - } - - if (this._isSpecialKey(keyCode) === false && event.metaKey === false) { - this.expand(); - - if (this.get("filterable") === true || this.get("autoFilterable")) { - this.set("renderedFilterOnce", true); - } - - Ember.run.schedule("afterRender", () => { - this.$filterInput() - .focus() - .val(this.$filterInput().val() + String.fromCharCode(keyCode)); - }); - } - }); - - this.$filterInput() - .on("change.select-box-kit", (event) => { - this.send("onFilterChange", $(event.target).val()); - }) - .on("keydown.select-box-kit", (event) => { - const keyCode = event.keyCode || event.which; - - if (keyCode === this.keys.TAB) { this._handleTabOnKeyDown(event); } - if (keyCode === this.keys.ESC) { this._handleEscOnKeyDown(event); } - if (keyCode === this.keys.UP || keyCode === this.keys.DOWN) { - this._handleArrowKey(keyCode, event); - } - }) - .on("keypress.select-box-kit", (event) => { - const keyCode = event.keyCode || event.which; - - if ([ - this.keys.RIGHT, - this.keys.LEFT, - this.keys.BACKSPACE, - this.keys.SPACE, - ].includes(keyCode) || event.metaKey === true) { - return true; - } - - if (keyCode === this.keys.TAB && this.get("isExpanded") === false) { - return true; - } - - if (this._isSpecialKey(keyCode) === true) { - this.$offscreenInput().focus().trigger(event); - return false; - } - - return true; - }); - }, - - _handleEscOnKeyDown(event) { - this.unfocus(); - this._killEvent(event); - }, - - _handleTabOnKeyDown(event) { - if (this.get("isExpanded") === false) { - this.unfocus(); - return true; - } else if (this.$highlightedRow().length === 1) { - this._killEvent(event); - this.$highlightedRow().click(); - this.focus(); - } else { - this.unfocus(); - return true; - } - return false; - }, - - _handleArrowKey(keyCode, event) { - if (this.get("isExpanded") === false) { this.expand(); } - this._killEvent(event); - const $rows = this.$rows(); - - if ($rows.length <= 0) { return; } - if ($rows.length === 1) { - this._rowSelection($rows, 0); - return; - } - - const direction = keyCode === 38 ? -1 : 1; - - Ember.run.throttle(this, this._moveHighlight, direction, $rows, 32); - }, - - _moveHighlight(direction, $rows) { - const currentIndex = $rows.index(this.$highlightedRow()); - let nextIndex = currentIndex + direction; - - if (nextIndex < 0) { - nextIndex = $rows.length - 1; - } else if (nextIndex >= $rows.length) { - nextIndex = 0; - } - - this._rowSelection($rows, nextIndex); - }, - - _rowSelection($rows, nextIndex) { - const highlightableValue = $rows.eq(nextIndex).attr("data-value"); - const $highlightableRow = this.$findRowByValue(highlightableValue); - - Ember.run.schedule("afterRender", () => { - $highlightableRow.trigger("mouseover").focus(); - this.focus(); - }); - }, - - _isSpecialKey(keyCode) { - return _.values(this.keys).includes(keyCode); - }, -}); diff --git a/app/assets/javascripts/select-box-kit/templates/components/combo-box/combo-box-header.hbs b/app/assets/javascripts/select-box-kit/templates/components/combo-box/combo-box-header.hbs deleted file mode 100644 index 38e070fa345..00000000000 --- a/app/assets/javascripts/select-box-kit/templates/components/combo-box/combo-box-header.hbs +++ /dev/null @@ -1,15 +0,0 @@ -{{#if icon}} - {{{icon}}} -{{/if}} - - - {{{selectedName}}} - - -{{#if shouldDisplayClearableButton}} - -{{/if}} - -{{d-icon caretIcon class="caret-icon"}} diff --git a/app/assets/javascripts/select-box-kit/templates/components/dropdown-select-box/dropdown-select-box-header.hbs b/app/assets/javascripts/select-box-kit/templates/components/dropdown-select-box/dropdown-select-box-header.hbs deleted file mode 100644 index 0129d1651fd..00000000000 --- a/app/assets/javascripts/select-box-kit/templates/components/dropdown-select-box/dropdown-select-box-header.hbs +++ /dev/null @@ -1,18 +0,0 @@ - diff --git a/app/assets/javascripts/select-box-kit/templates/components/multi-combo-box/multi-combo-box-header.hbs b/app/assets/javascripts/select-box-kit/templates/components/multi-combo-box/multi-combo-box-header.hbs deleted file mode 100644 index 6245b4e8c7b..00000000000 --- a/app/assets/javascripts/select-box-kit/templates/components/multi-combo-box/multi-combo-box-header.hbs +++ /dev/null @@ -1,13 +0,0 @@ - diff --git a/app/assets/javascripts/select-box-kit/templates/components/multi-combo-box/selected-name.hbs b/app/assets/javascripts/select-box-kit/templates/components/multi-combo-box/selected-name.hbs deleted file mode 100644 index 54ef362ed31..00000000000 --- a/app/assets/javascripts/select-box-kit/templates/components/multi-combo-box/selected-name.hbs +++ /dev/null @@ -1,9 +0,0 @@ - - {{#unless isLocked}} - - {{d-icon "times"}} - - {{/unless}} - - {{content.name}} - diff --git a/app/assets/javascripts/select-box-kit/templates/components/select-box-kit/select-box-kit-header.hbs b/app/assets/javascripts/select-box-kit/templates/components/select-box-kit/select-box-kit-header.hbs deleted file mode 100644 index b0cea9f9134..00000000000 --- a/app/assets/javascripts/select-box-kit/templates/components/select-box-kit/select-box-kit-header.hbs +++ /dev/null @@ -1,7 +0,0 @@ -{{#if icon}} - {{{icon}}} -{{/if}} - - - {{{selectedName}}} - diff --git a/app/assets/javascripts/select-box-kit/templates/components/select-box-kit/select-box-kit-row.hbs b/app/assets/javascripts/select-box-kit/templates/components/select-box-kit/select-box-kit-row.hbs deleted file mode 100644 index 1786cfb5538..00000000000 --- a/app/assets/javascripts/select-box-kit/templates/components/select-box-kit/select-box-kit-row.hbs +++ /dev/null @@ -1,9 +0,0 @@ -{{#if template}} - {{{template}}} -{{else}} - {{#if icon}} - {{{icon}}} - {{/if}} - - {{content.name}} -{{/if}} diff --git a/app/assets/javascripts/select-box-kit/components/admin-agree-flag-dropdown.js.es6 b/app/assets/javascripts/select-kit/components/admin-agree-flag-dropdown.js.es6 similarity index 76% rename from app/assets/javascripts/select-box-kit/components/admin-agree-flag-dropdown.js.es6 rename to app/assets/javascripts/select-kit/components/admin-agree-flag-dropdown.js.es6 index cca1e5c76cc..55708f10eaa 100644 --- a/app/assets/javascripts/select-box-kit/components/admin-agree-flag-dropdown.js.es6 +++ b/app/assets/javascripts/select-kit/components/admin-agree-flag-dropdown.js.es6 @@ -1,21 +1,18 @@ -import { iconHTML } from 'discourse-common/lib/icon-library'; -import DropdownSelectBox from "select-box-kit/components/dropdown-select-box"; +import DropdownSelectBox from "select-kit/components/dropdown-select-box"; import computed from "ember-addons/ember-computed-decorators"; -import { on } from "ember-addons/ember-computed-decorators"; export default DropdownSelectBox.extend({ - headerText: "admin.flags.agree", - headerIcon: "thumbs-o-up", + pluginApiIdentifiers: ["admin-agree-flag-dropdown"], classNames: ["agree-flag", "admin-agree-flag-dropdown"], adminTools: Ember.inject.service(), nameProperty: "label", + allowInitialValueMutation: false, + headerIcon: "thumbs-o-up", - @on("didReceiveAttrs") - _setAdminAgreeDropdownOptions() { - this.get('headerComponentOptions').setProperties({ - selectedName: `${I18n.t(this.get("headerText"))} ...`, - icon: iconHTML("thumbs-o-up") - }); + computeHeaderContent() { + let content = this.baseHeaderComputedContent(); + content.name = `${I18n.t("admin.flags.agree")}...`; + return content; }, @computed("adminTools", "post.user") @@ -25,9 +22,10 @@ export default DropdownSelectBox.extend({ canDeleteSpammer: Ember.computed.and("spammerDetails.canDelete", "post.flaggedForSpam"), - @computed("post", "canDeleteSpammer") - content(post, canDeleteSpammer) { + computeContent() { const content = []; + const post = this.get("post"); + const canDeleteSpammer = this.get("canDeleteSpammer"); if (post.user_deleted) { content.push({ @@ -70,8 +68,9 @@ export default DropdownSelectBox.extend({ return content; }, - selectValueFunction(value) { - Ember.get(this._contentForValue(value), "action")(); + mutateValue(value) { + const computedContentItem = this.get("computedContent").findBy("value", value); + Ember.get(computedContentItem, "originalContent.action")(); }, actions: { diff --git a/app/assets/javascripts/select-box-kit/components/admin-delete-flag-dropdown.js.es6 b/app/assets/javascripts/select-kit/components/admin-delete-flag-dropdown.js.es6 similarity index 74% rename from app/assets/javascripts/select-box-kit/components/admin-delete-flag-dropdown.js.es6 rename to app/assets/javascripts/select-kit/components/admin-delete-flag-dropdown.js.es6 index 8b130c2c8b9..2144a1512a6 100644 --- a/app/assets/javascripts/select-box-kit/components/admin-delete-flag-dropdown.js.es6 +++ b/app/assets/javascripts/select-kit/components/admin-delete-flag-dropdown.js.es6 @@ -1,20 +1,16 @@ -import { iconHTML } from 'discourse-common/lib/icon-library'; -import DropdownSelectBox from "select-box-kit/components/dropdown-select-box"; +import DropdownSelectBox from "select-kit/components/dropdown-select-box"; import computed from "ember-addons/ember-computed-decorators"; -import { on } from "ember-addons/ember-computed-decorators"; export default DropdownSelectBox.extend({ - headerText: "admin.flags.delete", classNames: ["delete-flag", "admin-delete-flag-dropdown"], adminTools: Ember.inject.service(), nameProperty: "label", + headerIcon: "trash-o", - @on("didReceiveAttrs") - _setAdminDeleteDropdownOptions() { - this.get('headerComponentOptions').setProperties({ - selectedName: `${I18n.t(this.get("headerText"))} ...`, - icon: iconHTML("trash-o") - }); + computeHeaderContent() { + let content = this.baseHeaderComputedContent(); + content.name = I18n.t("admin.flags.delete"); + return content; }, @computed("adminTools", "post.user") @@ -24,9 +20,9 @@ export default DropdownSelectBox.extend({ canDeleteSpammer: Ember.computed.and("spammerDetails.canDelete", "post.flaggedForSpam"), - @computed("post", "canDeleteSpammer") - content(post, canDeleteSpammer) { + computeContent() { const content = []; + const canDeleteSpammer = this.get("canDeleteSpammer"); content.push({ icon: "external-link", @@ -57,8 +53,9 @@ export default DropdownSelectBox.extend({ return content; }, - selectValueFunction(value) { - Ember.get(this._contentForValue(value), "action")(); + mutateValue(value) { + const computedContentItem = this.get("computedContent").findBy("value", value); + Ember.get(computedContentItem, "originalContent.action")(); }, actions: { diff --git a/app/assets/javascripts/select-kit/components/admin-group-selector.js.es6 b/app/assets/javascripts/select-kit/components/admin-group-selector.js.es6 new file mode 100644 index 00000000000..be3352b376b --- /dev/null +++ b/app/assets/javascripts/select-kit/components/admin-group-selector.js.es6 @@ -0,0 +1,51 @@ +import MultiSelectComponent from "select-kit/components/multi-select"; +const { makeArray } = Ember; + +export default MultiSelectComponent.extend({ + pluginApiIdentifiers: ["admin-group-selector"], + classNames: "admin-group-selector", + selected: null, + available: null, + allowAny: false, + + computeValues() { + return makeArray(this.get("selected")) + .map(s => this.valueForContentItem(s)); + }, + + computeContent() { + return makeArray(this.get("available")); + }, + + computeContentItem(contentItem, name) { + let computedContent = this.baseComputedContentItem(contentItem, name); + computedContent.locked = contentItem.automatic; + return computedContent; + }, + + mutateValues(values) { + if (values.length > this.get("selected").length) { + const newValues = values + .filter(v => !this.get("selected") + .map(s => this.valueForContentItem(s)) + .includes(v)); + + newValues.forEach(value => { + const actionContext = this.get("available") + .findBy(this.get("valueAttribute"), parseInt(value, 10)); + + this.triggerAction({ action: "groupAdded", actionContext }); + }); + } else if (values.length < this.get("selected").length) { + const selected = this.get("selected") + .filter(s => !values.includes(this.valueForContentItem(s))); + + selected.forEach(s => { + this.triggerAction({ + action: "groupRemoved", + actionContext: this.valueForContentItem(s) + }); + }); + } + } +}); diff --git a/app/assets/javascripts/select-box-kit/components/categories-admin-dropdown.js.es6 b/app/assets/javascripts/select-kit/components/categories-admin-dropdown.js.es6 similarity index 51% rename from app/assets/javascripts/select-box-kit/components/categories-admin-dropdown.js.es6 rename to app/assets/javascripts/select-kit/components/categories-admin-dropdown.js.es6 index 187a710b880..63f1bac5499 100644 --- a/app/assets/javascripts/select-box-kit/components/categories-admin-dropdown.js.es6 +++ b/app/assets/javascripts/select-kit/components/categories-admin-dropdown.js.es6 @@ -1,21 +1,15 @@ -import DropdownSelectBoxComponent from "select-box-kit/components/dropdown-select-box"; -import { iconHTML } from "discourse-common/lib/icon-library"; -import computed from "ember-addons/ember-computed-decorators"; -import { on } from "ember-addons/ember-computed-decorators"; +import DropdownSelectBoxComponent from "select-kit/components/dropdown-select-box"; export default DropdownSelectBoxComponent.extend({ + pluginApiIdentifiers: ["categories-admin-dropdown"], classNames: "categories-admin-dropdown", + showFullTitle: false, + allowInitialValueMutation: false, + headerIcon: ["bars", "caret-down"], - @on("didReceiveAttrs") - _setComponentOptions() { - this.get("headerComponentOptions").setProperties({ - shouldDisplaySelectedName: false, - icon: `${iconHTML('bars')}${iconHTML('caret-down')}`.htmlSafe(), - }); - }, + autoHighlight() {}, - @computed - content() { + computeContent() { const items = [ { id: "create", @@ -38,8 +32,7 @@ export default DropdownSelectBoxComponent.extend({ return items; }, - selectValueFunction(value) { + mutateValue(value) { this.get(value)(); - this.set("value", null); } }); diff --git a/app/assets/javascripts/select-kit/components/category-chooser.js.es6 b/app/assets/javascripts/select-kit/components/category-chooser.js.es6 new file mode 100644 index 00000000000..47a319e066a --- /dev/null +++ b/app/assets/javascripts/select-kit/components/category-chooser.js.es6 @@ -0,0 +1,92 @@ +import ComboBoxComponent from "select-kit/components/combo-box"; +import { on } from "ember-addons/ember-computed-decorators"; +import computed from "ember-addons/ember-computed-decorators"; +import PermissionType from "discourse/models/permission-type"; +import Category from "discourse/models/category"; +const { get, isNone, isEmpty } = Ember; + +export default ComboBoxComponent.extend({ + pluginApiIdentifiers: ["category-chooser"], + classNames: "category-chooser", + filterable: true, + castInteger: true, + allowUncategorized: false, + rowComponent: "category-row", + noneRowComponent: "none-category-row", + allowSubCategories: true, + + filterComputedContent(computedContent, computedValue, filter) { + if (isEmpty(filter)) { return computedContent; } + + const _matchFunction = (f, text) => { + return text.toLowerCase().indexOf(f) > -1; + }; + const lowerFilter = filter.toLowerCase(); + + return computedContent.filter(c => { + const category = Category.findById(get(c, "value")); + const text = get(c, "name"); + if (category && category.get("parentCategory")) { + const categoryName = category.get("parentCategory.name"); + return _matchFunction(lowerFilter, text) || _matchFunction(lowerFilter, categoryName); + } else { + return _matchFunction(lowerFilter, text); + } + }); + }, + + @computed("rootNone", "rootNoneLabel") + none(rootNone, rootNoneLabel) { + if (this.siteSettings.allow_uncategorized_topics || this.get("allowUncategorized")) { + if (!isNone(rootNone)) { + return rootNoneLabel || "category.none"; + } else { + return Category.findUncategorized(); + } + } else { + return "category.choose"; + } + }, + + @on("didRender") + _bindComposerResizing() { + this.appEvents.on("composer:resized", this, this.applyDirection); + }, + + @on("willDestroyElement") + _unbindComposerResizing() { + this.appEvents.off("composer:resized"); + }, + + computeContent() { + const categories = Discourse.SiteSettings.fixed_category_positions_on_create ? + Category.list() : + Category.listByActivity(); + + let scopedCategoryId = this.get("scopedCategoryId"); + if (scopedCategoryId) { + const scopedCat = Category.findById(scopedCategoryId); + scopedCategoryId = scopedCat.get("parent_category_id") || scopedCat.get("id"); + } + + const excludeCategoryId = this.get("excludeCategoryId"); + + return categories.filter(c => { + const categoryId = this.valueForContentItem(c); + + if (scopedCategoryId && categoryId !== scopedCategoryId && get(c, "parent_category_id") !== scopedCategoryId) { + return false; + } + + if (this.get("allowSubCategories") === false && c.get("parentCategory") ) { + return false; + } + + if ((this.get("allowUncategorized") === false && get(c, "isUncategorizedCategory")) || excludeCategoryId === categoryId) { + return false; + } + + return get(c, "permission") === PermissionType.FULL; + }); + } +}); diff --git a/app/assets/javascripts/select-kit/components/category-notifications-button.js.es6 b/app/assets/javascripts/select-kit/components/category-notifications-button.js.es6 new file mode 100644 index 00000000000..f84c0ba4c2f --- /dev/null +++ b/app/assets/javascripts/select-kit/components/category-notifications-button.js.es6 @@ -0,0 +1,20 @@ +import NotificationOptionsComponent from "select-kit/components/notifications-button"; +import computed from "ember-addons/ember-computed-decorators"; + +export default NotificationOptionsComponent.extend({ + pluginApiIdentifiers: ["category-notifications-button"], + classNames: "category-notifications-button", + isHidden: Ember.computed.or("category.deleted", "site.isMobileDevice"), + i18nPrefix: "category.notifications", + showFullTitle: false, + allowInitialValueMutation: false, + + mutateValue(value) { + this.get("category").setNotification(value); + }, + + @computed("iconForSelectedDetails") + headerIcon(iconForSelectedDetails) { + return [iconForSelectedDetails, "caret-down"]; + } +}); diff --git a/app/assets/javascripts/select-kit/components/category-row.js.es6 b/app/assets/javascripts/select-kit/components/category-row.js.es6 new file mode 100644 index 00000000000..b3470102296 --- /dev/null +++ b/app/assets/javascripts/select-kit/components/category-row.js.es6 @@ -0,0 +1,63 @@ +import SelectKitRowComponent from "select-kit/components/select-kit/select-kit-row"; +import computed from "ember-addons/ember-computed-decorators"; +import Category from "discourse/models/category"; +import { categoryBadgeHTML } from "discourse/helpers/category-link"; + +export default SelectKitRowComponent.extend({ + layoutName: "select-kit/templates/components/category-row", + classNames: "category-row", + displayCategoryDescription: true, + + @computed("computedContent.value", "computedContent.name") + category(value, name) { + if (Ember.isEmpty(value)) { + const uncat = Category.findUncategorized(); + if (uncat && uncat.get("name") === name) { + return uncat; + } + } else { + return Category.findById(parseInt(value, 10)); + } + }, + + @computed("category") + badgeForCategory(category) { + return categoryBadgeHTML(category, { + link: false, + allowUncategorized: true, + hideParent: true + }).htmlSafe(); + }, + + @computed("parentCategory") + badgeForParentCategory(parentCategory) { + return categoryBadgeHTML(parentCategory, {link: false}).htmlSafe(); + }, + + @computed("parentCategoryid") + parentCategory(parentCategoryId) { + return Category.findById(parentCategoryId); + }, + + @computed("parentCategoryid") + hasParentCategory(parentCategoryid) { + return !Ember.isNone(parentCategoryid); + }, + + @computed("category") + parentCategoryid(category) { + return category.get("parent_category_id"); + }, + + topicCount: Ember.computed.alias("category.topic_count"), + + @computed("options.displayCategoryDescription", "category.description") + hasDescription(displayCategoryDescription, description) { + return displayCategoryDescription && description && description !== "null"; + }, + + @computed("category.description") + description(description) { + return `${description.substr(0, 200)}${description.length > 200 ? '…' : ''}`; + } +}); diff --git a/app/assets/javascripts/select-kit/components/category-selector.js.es6 b/app/assets/javascripts/select-kit/components/category-selector.js.es6 new file mode 100644 index 00000000000..9305517bf99 --- /dev/null +++ b/app/assets/javascripts/select-kit/components/category-selector.js.es6 @@ -0,0 +1,40 @@ +import MultiSelectComponent from "select-kit/components/multi-select"; +import Category from "discourse/models/category"; + +export default MultiSelectComponent.extend({ + pluginApiIdentifiers: ["category-selector"], + classNames: "category-selector", + filterable: true, + allowAny: false, + rowComponent: "category-row", + + init() { + this._super(); + + this.set("headerComponentOptions", Ember.Object.create({ + selectedNameComponent: "multi-select/selected-category" + })); + + this.set("rowComponentOptions", Ember.Object.create({ + displayCategoryDescription: false + })); + }, + + computeValues() { + return Ember.makeArray(this.get("categories")).map(c => c.id); + }, + + mutateValues(values) { + this.set("categories", values.map(v => Category.findById(v))); + }, + + filterComputedContent(computedContent, computedValues, filter) { + const regex = new RegExp(filter.toLowerCase(), 'i'); + return computedContent.filter(category => Ember.get(category, "name").match(regex)); + }, + + computeContent() { + const blacklist = Ember.makeArray(this.get("blacklist")); + return Category.list().filter(category => !blacklist.includes(category)); + } +}); diff --git a/app/assets/javascripts/select-box-kit/components/combo-box.js.es6 b/app/assets/javascripts/select-kit/components/combo-box.js.es6 similarity index 61% rename from app/assets/javascripts/select-box-kit/components/combo-box.js.es6 rename to app/assets/javascripts/select-kit/components/combo-box.js.es6 index 26779a38949..0a576eae9af 100644 --- a/app/assets/javascripts/select-box-kit/components/combo-box.js.es6 +++ b/app/assets/javascripts/select-kit/components/combo-box.js.es6 @@ -1,7 +1,8 @@ -import SelectBoxKitComponent from "select-box-kit/components/select-box-kit"; +import SingleSelectComponent from "select-kit/components/single-select"; import { on } from "ember-addons/ember-computed-decorators"; -export default SelectBoxKitComponent.extend({ +export default SingleSelectComponent.extend({ + pluginApiIdentifiers: ["combo-box"], classNames: "combobox combo-box", autoFilterable: true, headerComponent: "combo-box/combo-box-header", @@ -10,6 +11,12 @@ export default SelectBoxKitComponent.extend({ caretDownIcon: "caret-down", clearable: false, + computeHeaderContent() { + let content = this.baseHeaderComputedContent(); + content.hasSelection = this.get("hasSelection"); + return content; + }, + @on("didReceiveAttrs") _setComboBoxOptions() { this.get("headerComponentOptions").setProperties({ diff --git a/app/assets/javascripts/select-kit/components/combo-box/combo-box-header.js.es6 b/app/assets/javascripts/select-kit/components/combo-box/combo-box-header.js.es6 new file mode 100644 index 00000000000..6cc5ecd21f7 --- /dev/null +++ b/app/assets/javascripts/select-kit/components/combo-box/combo-box-header.js.es6 @@ -0,0 +1,21 @@ +import SelectKitHeaderComponent from "select-kit/components/select-kit/select-kit-header"; +import { default as computed } from "ember-addons/ember-computed-decorators"; + +export default SelectKitHeaderComponent.extend({ + layoutName: "select-kit/templates/components/combo-box/combo-box-header", + classNames: "combo-box-header", + + clearable: Ember.computed.alias("options.clearable"), + caretUpIcon: Ember.computed.alias("options.caretUpIcon"), + caretDownIcon: Ember.computed.alias("options.caretDownIcon"), + + @computed("isExpanded", "caretUpIcon", "caretDownIcon") + caretIcon(isExpanded, caretUpIcon, caretDownIcon) { + return isExpanded === true ? caretUpIcon : caretDownIcon; + }, + + @computed("clearable", "computedContent.hasSelection") + shouldDisplayClearableButton(clearable, hasSelection) { + return clearable === true && hasSelection === true; + } +}); diff --git a/app/assets/javascripts/select-kit/components/dropdown-select-box.js.es6 b/app/assets/javascripts/select-kit/components/dropdown-select-box.js.es6 new file mode 100644 index 00000000000..8e7636445a1 --- /dev/null +++ b/app/assets/javascripts/select-kit/components/dropdown-select-box.js.es6 @@ -0,0 +1,32 @@ +import SingleSelectComponent from "select-kit/components/single-select"; +import { on } from "ember-addons/ember-computed-decorators"; + +export default SingleSelectComponent.extend({ + pluginApiIdentifiers: ["dropdown-select-box"], + classNames: "dropdown-select-box", + verticalOffset: 3, + fullWidthOnMobile: true, + filterable: false, + autoFilterable: false, + headerComponent: "dropdown-select-box/dropdown-select-box-header", + rowComponent: "dropdown-select-box/dropdown-select-box-row", + showFullTitle: true, + allowInitialValueMutation: false, + + @on("didReceiveAttrs") + _setDropdownSelectBoxComponentOptions() { + this.get("headerComponentOptions").setProperties({ + showFullTitle: this.get("showFullTitle") + }); + }, + + didClickOutside() { + if (this.get("isExpanded") === false) { return; } + this.close(); + }, + + didSelect() { + this._super(); + this.close(); + } +}); diff --git a/app/assets/javascripts/select-kit/components/dropdown-select-box/dropdown-select-box-header.js.es6 b/app/assets/javascripts/select-kit/components/dropdown-select-box/dropdown-select-box-header.js.es6 new file mode 100644 index 00000000000..d7e08764309 --- /dev/null +++ b/app/assets/javascripts/select-kit/components/dropdown-select-box/dropdown-select-box-header.js.es6 @@ -0,0 +1,15 @@ +import SelectKitHeaderComponent from "select-kit/components/select-kit/select-kit-header"; +import computed from "ember-addons/ember-computed-decorators"; + +export default SelectKitHeaderComponent.extend({ + layoutName: "select-kit/templates/components/dropdown-select-box/dropdown-select-box-header", + classNames: "dropdown-select-box-header", + tagName: "button", + + classNameBindings: ["btnClassName"], + + @computed("options.showFullTitle") + btnClassName(showFullTitle) { + return `btn ${showFullTitle ? 'btn-icon-text' : 'no-text btn-icon'}`; + } +}); diff --git a/app/assets/javascripts/select-kit/components/dropdown-select-box/dropdown-select-box-row.js.es6 b/app/assets/javascripts/select-kit/components/dropdown-select-box/dropdown-select-box-row.js.es6 new file mode 100644 index 00000000000..fd865fb6021 --- /dev/null +++ b/app/assets/javascripts/select-kit/components/dropdown-select-box/dropdown-select-box-row.js.es6 @@ -0,0 +1,9 @@ +import SelectKitRowComponent from "select-kit/components/select-kit/select-kit-row"; + +export default SelectKitRowComponent.extend({ + layoutName: "select-kit/templates/components/dropdown-select-box/dropdown-select-box-row", + classNames: "dropdown-select-box-row", + + name: Ember.computed.alias("computedContent.name"), + description: Ember.computed.alias("computedContent.originalContent.description") +}); diff --git a/app/assets/javascripts/select-box-kit/components/future-date-input-selector.js.es6 b/app/assets/javascripts/select-kit/components/future-date-input-selector.js.es6 similarity index 79% rename from app/assets/javascripts/select-box-kit/components/future-date-input-selector.js.es6 rename to app/assets/javascripts/select-kit/components/future-date-input-selector.js.es6 index b344f2080e6..961c7c2cf97 100644 --- a/app/assets/javascripts/select-box-kit/components/future-date-input-selector.js.es6 +++ b/app/assets/javascripts/select-kit/components/future-date-input-selector.js.es6 @@ -1,7 +1,6 @@ -import { default as computed, observes } from "ember-addons/ember-computed-decorators"; -import ComboBoxComponent from "select-box-kit/components/combo-box"; +import ComboBoxComponent from "select-kit/components/combo-box"; import { CLOSE_STATUS_TYPE } from "discourse/controllers/edit-topic-timer"; -import DatetimeMixin from "select-box-kit/components/future-date-input-selector/mixin"; +import DatetimeMixin from "select-kit/components/future-date-input-selector/mixin"; const TIMEFRAME_BASE = { enabled: () => true, @@ -112,14 +111,30 @@ export function timeframeDetails(id) { export const FORMAT = "YYYY-MM-DD HH:mm"; export default ComboBoxComponent.extend(DatetimeMixin, { + pluginApiIdentifiers: ["future-date-input-selector"], classNames: ["future-date-input-selector"], isCustom: Ember.computed.equal("value", "pick_date_and_time"), clearable: true, rowComponent: "future-date-input-selector/future-date-input-selector-row", headerComponent: "future-date-input-selector/future-date-input-selector-header", - @computed - content() { + computeHeaderContent() { + let content = this.baseHeaderComputedContent(); + content.datetime = this._computeDatetimeForValue(this.get("computedValue")); + content.name = this.get("selectedComputedContent.name") || content.name; + content.hasSelection = this.get("hasSelection"); + content.icons = this._computeIconsForValue(this.get("computedValue")); + return content; + }, + + computeContentItem(contentItem, name) { + let item = this.baseComputedContentItem(contentItem, name); + item.datetime = this._computeDatetimeForValue(contentItem.id); + item.icons = this._computeIconsForValue(contentItem.id); + return item; + }, + + computeContent() { let now = moment(); let opts = { now, @@ -138,21 +153,15 @@ export default ComboBoxComponent.extend(DatetimeMixin, { }); }, - @observes("value") - _updateInput() { + mutateValue(value) { if (this.get("isCustom")) return; let input = null; - const { time } = this.get("updateAt"); + const { time } = this._updateAt(value); - if (time && !Ember.isEmpty(this.get("value"))) { + if (time && !Ember.isEmpty(value)) { input = time.format(FORMAT); } - this.set("input", input); + this.setProperties({ input, value }); }, - - @computed("value") - updateAt(value) { - return this._updateAt(value); - } }); diff --git a/app/assets/javascripts/select-kit/components/future-date-input-selector/future-date-input-selector-header.js.es6 b/app/assets/javascripts/select-kit/components/future-date-input-selector/future-date-input-selector-header.js.es6 new file mode 100644 index 00000000000..7a5e8075381 --- /dev/null +++ b/app/assets/javascripts/select-kit/components/future-date-input-selector/future-date-input-selector-header.js.es6 @@ -0,0 +1,6 @@ +import ComboBoxHeaderComponent from "select-kit/components/combo-box/combo-box-header"; + +export default ComboBoxHeaderComponent.extend({ + layoutName: "select-kit/templates/components/future-date-input-selector/future-date-input-selector-header", + classNames: "future-date-input-selector-header" +}); diff --git a/app/assets/javascripts/select-kit/components/future-date-input-selector/future-date-input-selector-row.js.es6 b/app/assets/javascripts/select-kit/components/future-date-input-selector/future-date-input-selector-row.js.es6 new file mode 100644 index 00000000000..a04a59507b1 --- /dev/null +++ b/app/assets/javascripts/select-kit/components/future-date-input-selector/future-date-input-selector-row.js.es6 @@ -0,0 +1,6 @@ +import SelectKitRowComponent from "select-kit/components/select-kit/select-kit-row"; + +export default SelectKitRowComponent.extend({ + layoutName: "select-kit/templates/components/future-date-input-selector/future-date-input-selector-row", + classNames: "future-date-input-selector-row" +}); diff --git a/app/assets/javascripts/select-box-kit/components/future-date-input-selector/mixin.js.es6 b/app/assets/javascripts/select-kit/components/future-date-input-selector/mixin.js.es6 similarity index 76% rename from app/assets/javascripts/select-box-kit/components/future-date-input-selector/mixin.js.es6 rename to app/assets/javascripts/select-kit/components/future-date-input-selector/mixin.js.es6 index d69b38a5666..63689570562 100644 --- a/app/assets/javascripts/select-box-kit/components/future-date-input-selector/mixin.js.es6 +++ b/app/assets/javascripts/select-kit/components/future-date-input-selector/mixin.js.es6 @@ -1,16 +1,15 @@ -import { iconHTML } from 'discourse-common/lib/icon-library'; import { CLOSE_STATUS_TYPE } from 'discourse/controllers/edit-topic-timer'; -import { timeframeDetails } from 'select-box-kit/components/future-date-input-selector'; +import { timeframeDetails } from 'select-kit/components/future-date-input-selector'; export default Ember.Mixin.create({ - _computeIconForValue(value) { + _computeIconsForValue(value) { let {icon} = this._updateAt(value); if (icon) { - return icon.split(",").map(i => iconHTML(i)).join(" "); + return icon.split(","); } - return null; + return []; }, _computeDatetimeForValue(value) { @@ -20,7 +19,6 @@ export default Ember.Mixin.create({ let {time} = this._updateAt(value); if (time) { - let details = timeframeDetails(value); if (!details.displayWhen) { time = null; @@ -34,6 +32,7 @@ export default Ember.Mixin.create({ _updateAt(selection) { let details = timeframeDetails(selection); + if (details) { return { time: details.when(moment(), this.get('statusType') !== CLOSE_STATUS_TYPE ? 8 : 18), diff --git a/app/assets/javascripts/select-box-kit/components/group-notifications-button.js.es6 b/app/assets/javascripts/select-kit/components/group-notifications-button.js.es6 similarity index 51% rename from app/assets/javascripts/select-box-kit/components/group-notifications-button.js.es6 rename to app/assets/javascripts/select-kit/components/group-notifications-button.js.es6 index e30b4ec62fc..8236e4bbe14 100644 --- a/app/assets/javascripts/select-box-kit/components/group-notifications-button.js.es6 +++ b/app/assets/javascripts/select-kit/components/group-notifications-button.js.es6 @@ -1,11 +1,12 @@ -import NotificationOptionsComponent from "select-box-kit/components/notifications-button"; +import NotificationOptionsComponent from "select-kit/components/notifications-button"; export default NotificationOptionsComponent.extend({ + pluginApiIdentifiers: ["grouo-notifications-button"], classNames: ["group-notifications-button"], - value: Ember.computed.alias("group.group_user.notification_level"), i18nPrefix: "groups.notifications", + allowInitialValueMutation: false, - selectValueFunction(value) { + mutateValue(value) { this.get("group").setNotification(value, this.get("user.id")); } }); diff --git a/app/assets/javascripts/select-kit/components/list-setting.js.es6 b/app/assets/javascripts/select-kit/components/list-setting.js.es6 new file mode 100644 index 00000000000..0872aab9510 --- /dev/null +++ b/app/assets/javascripts/select-kit/components/list-setting.js.es6 @@ -0,0 +1,54 @@ +import MultiSelectComponent from "select-kit/components/multi-select"; + +export default MultiSelectComponent.extend({ + pluginApiIdentifiers: ["list-setting"], + classNames: "list-setting", + tokenSeparator: "|", + settingValue: "", + choices: null, + filterable: true, + + init() { + this._super(); + + if (!Ember.isNone(this.get("settingName"))) { + this.set("nameProperty", this.get("settingName")); + } + + if (this.get("nameProperty").indexOf("color") > -1) { + this.set("headerComponentOptions", Ember.Object.create({ + selectedNameComponent: "multi-select/selected-color" + })); + } + }, + + computeContent() { + let content; + if (Ember.isNone(this.get("choices"))) { + content = this.get("settingValue").split(this.get("tokenSeparator"));; + } else { + content = this.get("choices"); + } + + return Ember.makeArray(content).filter(c => c); + }, + + mutateValues(values) { + this.set("settingValue", values.join(this.get("tokenSeparator"))); + }, + + computeValues() { + return this.get("settingValue") + .split(this.get("tokenSeparator")) + .filter(c => c); + }, + + _handleTabOnKeyDown(event) { + if (this.$highlightedRow().length === 1) { + this._super(event); + } else { + this.close(); + return false; + } + } +}); diff --git a/app/assets/javascripts/select-kit/components/multi-select.js.es6 b/app/assets/javascripts/select-kit/components/multi-select.js.es6 new file mode 100644 index 00000000000..ceb7e373919 --- /dev/null +++ b/app/assets/javascripts/select-kit/components/multi-select.js.es6 @@ -0,0 +1,255 @@ +import SelectKitComponent from "select-kit/components/select-kit"; +import computed from "ember-addons/ember-computed-decorators"; +import { on } from "ember-addons/ember-computed-decorators"; +const { get, isNone, isEmpty, makeArray } = Ember; + +export default SelectKitComponent.extend({ + pluginApiIdentifiers: ["multi-select"], + classNames: "multi-select", + headerComponent: "multi-select/multi-select-header", + filterComponent: null, + headerText: "select_kit.default_header_text", + allowAny: true, + allowInitialValueMutation: false, + autoFilterable: true, + selectedNameComponent: "multi-select/selected-name", + + init() { + this._super(); + + this.set("computedValues", []); + if (isNone(this.get("values"))) { this.set("values", []); } + + this.set("headerComponentOptions", Ember.Object.create({ + selectedNameComponent: this.get("selectedNameComponent") + })); + }, + + @on("didRender") + _setChoicesMaxWidth() { + const width = this.$body().outerWidth(false); + this.$(".choices").css({ maxWidth: width, width }); + }, + + @on("didReceiveAttrs") + _compute() { + Ember.run.scheduleOnce("afterRender", () => { + this.willComputeAttributes(); + let content = this._beforeWillComputeContent(this.get("content")); + content = this.willComputeContent(content); + let values = this._beforeWillComputeValues(this.get("values")); + content = this.computeContent(content); + content = this._beforeDidComputeContent(content); + values = this.willComputeValues(values); + values = this.computeValues(values); + values = this._beforeDidComputeValues(values); + this.set("headerComputedContent", this.computeHeaderContent()); + this.didComputeContent(content); + this.didComputeValues(values); + this.didComputeAttributes(); + }); + }, + + @computed("filter", "shouldDisplayCreateRow") + createRowComputedContent(filter, shouldDisplayCreateRow) { + if (shouldDisplayCreateRow === true) { + let content = this.createContentFromInput(filter); + return this.computeContentItem(content, { created: true }); + } + }, + + @computed("filter", "computedValues") + shouldDisplayCreateRow(filter, computedValues) { + return this._super() && !computedValues.includes(filter); + }, + + _beforeWillComputeValues(values) { + return values.map(v => this._castInteger(v === "" ? null : v)); + }, + willComputeValues(values) { return values; }, + computeValues(values) { return values; }, + _beforeDidComputeValues(values) { + this.setProperties({ computedValues: values }); + return values; + }, + didComputeValues(values) { return values; }, + + mutateAttributes() { + Ember.run.next(() => { + this.mutateContent(this.get("computedContent")); + this.mutateValues(this.get("computedValues")); + this.set("headerComputedContent", this.computeHeaderContent()); + }); + }, + mutateValues(computedValues) { this.set("values", computedValues); }, + + filterComputedContent(computedContent, computedValues, filter) { + const lowerFilter = filter.toLowerCase(); + return computedContent.filter(c => { + return get(c, "name").toLowerCase().indexOf(lowerFilter) > -1; + }); + }, + + @computed("computedContent.[]", "computedValues.[]", "filter") + filteredComputedContent(computedContent, computedValues, filter) { + computedContent = computedContent.filter(c => { + return !computedValues.includes(get(c, "value")); + }); + + if (this.get("shouldFilter") === true) { + computedContent = this.filterComputedContent(computedContent, computedValues, filter); + } + + return computedContent.slice(0, this.get("limitMatches")); + }, + + baseHeaderComputedContent() { + return { + selectedComputedContents: this.get("selectedComputedContents") + }; + }, + + @computed("filter") + templateForCreateRow() { + return (rowComponent) => { + return I18n.t("select_kit.create", { content: rowComponent.get("computedContent.name")}); + }; + }, + + didPressBackspace(event) { + this.expand(); + this.keyDown(event); + this._destroyEvent(event); + }, + + didPressEscape(event) { + const $highlighted = this.$(".selected-name.is-highlighted"); + if ($highlighted.length > 0) { + $highlighted.removeClass("is-highlighted"); + } + + this._super(event); + }, + + keyDown(event) { + if (!isEmpty(this.get("filter"))) return; + + const keyCode = event.keyCode || event.which; + const $filterInput = this.$filterInput(); + + // select all choices + if (this.get("hasSelection") && event.metaKey === true && keyCode === 65) { + this.$(".choices .selected-name:not(.is-locked)").addClass("is-highlighted"); + return false; + } + + // clear selection when multiple + if (this.$(".selected-name.is-highlighted").length >= 1 && keyCode === this.keys.BACKSPACE) { + const highlightedComputedContents = []; + $.each(this.$(".selected-name.is-highlighted"), (i, el) => { + const computedContent = this._findComputedContentItemByGuid($(el).attr("data-guid")); + if (!Ember.isNone(computedContent)) { highlightedComputedContents.push(computedContent); } + }); + this.send("onDeselect", highlightedComputedContents); + return; + } + + // try to remove last item from the list + if (keyCode === this.keys.BACKSPACE) { + let $lastSelectedValue = $(this.$(".choices .selected-name:not(.is-locked)").last()); + + if ($lastSelectedValue.length === 0) { return; } + + if ($filterInput.not(":visible") && $lastSelectedValue.length > 0) { + $lastSelectedValue.click(); + return false; + } + + if ($filterInput.val() === "") { + if ($filterInput.is(":focus")) { + if ($lastSelectedValue.length > 0) { $lastSelectedValue.click(); } + } else { + if ($lastSelectedValue.length > 0) { + $lastSelectedValue.click(); + } else { + $filterInput.focus(); + } + } + } + } + }, + + @computed("computedValues.[]", "computedContent.[]") + selectedComputedContents(computedValues, computedContent) { + const selected = []; + computedValues.forEach(v => selected.push(computedContent.findBy("value", v)) ); + return selected; + }, + + @computed("selectedComputedContents.[]") + hasSelection(selectedComputedContents) { return !Ember.isEmpty(selectedComputedContents); }, + + autoHighlight() { + Ember.run.schedule("afterRender", () => { + if (this.get("isExpanded") === false) { return; } + if (this.get("renderedBodyOnce") === false) { return; } + if (!isNone(this.get("highlightedValue"))) { return; } + + if (isEmpty(this.get("filteredComputedContent"))) { + if (this.get("createRowComputedContent")) { + this.send("onHighlight", this.get("createRowComputedContent")); + } else if (this.get("noneRowComputedContent") && this.get("hasSelection") === true) { + this.send("onHighlight", this.get("noneRowComputedContent")); + } + } else { + this.send("onHighlight", this.get("filteredComputedContent.firstObject")); + } + }); + }, + + didSelect() { + this.focus(); + this.autoHighlight(); + }, + + didDeselect() { + this.focus(); + this.autoHighlight(); + }, + + validateComputedContentItem(computedContentItem) { + return !this.get("computedValues").includes(computedContentItem.value); + }, + + actions: { + onClear() { + this.get("selectedComputedContents").forEach(selectedComputedContent => { + this.send("onDeselect", selectedComputedContent); + }); + }, + + onCreate(computedContentItem) { + if (this.validateComputedContentItem(computedContentItem)) { + this.get("computedContent").pushObject(computedContentItem); + this.send("onSelect", computedContentItem); + } + }, + + onSelect(computedContentItem) { + this.willSelect(computedContentItem); + this.get("computedValues").pushObject(computedContentItem.value); + Ember.run.next(() => this.mutateAttributes()); + Ember.run.schedule("afterRender", () => this.didSelect(computedContentItem)); + }, + + onDeselect(rowComputedContentItems) { + rowComputedContentItems = Ember.makeArray(rowComputedContentItems); + const generatedComputedContents = this._filterRemovableComputedContents(makeArray(rowComputedContentItems)); + this.willDeselect(rowComputedContentItems); + this.get("computedValues").removeObjects(rowComputedContentItems.map(r => r.value)); + this.get("computedContent").removeObjects(generatedComputedContents); + Ember.run.next(() => this.mutateAttributes()); + Ember.run.schedule("afterRender", () => this.didDeselect(rowComputedContentItems)); + } + } +}); diff --git a/app/assets/javascripts/select-box-kit/components/multi-combo-box/multi-combo-box-header.js.es6 b/app/assets/javascripts/select-kit/components/multi-select/multi-select-header.js.es6 similarity index 66% rename from app/assets/javascripts/select-box-kit/components/multi-combo-box/multi-combo-box-header.js.es6 rename to app/assets/javascripts/select-kit/components/multi-select/multi-select-header.js.es6 index 10e2d299ceb..d86af77ed8b 100644 --- a/app/assets/javascripts/select-box-kit/components/multi-combo-box/multi-combo-box-header.js.es6 +++ b/app/assets/javascripts/select-kit/components/multi-select/multi-select-header.js.es6 @@ -1,11 +1,11 @@ import { on } from "ember-addons/ember-computed-decorators"; import computed from "ember-addons/ember-computed-decorators"; -import SelectBoxKitHeaderComponent from "select-box-kit/components/select-box-kit/select-box-kit-header"; +import SelectKitHeaderComponent from "select-kit/components/select-kit/select-kit-header"; -export default SelectBoxKitHeaderComponent.extend({ +export default SelectKitHeaderComponent.extend({ attributeBindings: ["names:data-name"], - classNames: "multi-combo-box-header", - layoutName: "select-box-kit/templates/components/multi-combo-box/multi-combo-box-header", + classNames: "multi-select-header", + layoutName: "select-kit/templates/components/multi-select/multi-select-header", selectedNameComponent: Ember.computed.alias("options.selectedNameComponent"), @on("didRender") @@ -25,6 +25,8 @@ export default SelectBoxKitHeaderComponent.extend({ $filter.width(availableSpace - parentRightPadding * 4); }, - @computed("selectedContent.[]") - names(selectedContent) { return selectedContent.map(sc => sc.name).join(","); } + @computed("computedContent.selectedComputedContents.[]") + names(selectedComputedContents) { + return Ember.makeArray(selectedComputedContents).map(sc => sc.name).join(","); + } }); diff --git a/app/assets/javascripts/select-kit/components/multi-select/selected-category.js.es6 b/app/assets/javascripts/select-kit/components/multi-select/selected-category.js.es6 new file mode 100644 index 00000000000..0a09d69fabb --- /dev/null +++ b/app/assets/javascripts/select-kit/components/multi-select/selected-category.js.es6 @@ -0,0 +1,13 @@ +import SelectedNameComponent from "select-kit/components/multi-select/selected-name"; +import computed from "ember-addons/ember-computed-decorators"; +import { categoryBadgeHTML } from "discourse/helpers/category-link"; + +export default SelectedNameComponent.extend({ + classNames: "selected-category", + layoutName: "select-kit/templates/components/multi-select/selected-category", + + @computed("content.originalContent") + badge(category) { + return categoryBadgeHTML(category, {allowUncategorized: true, link: false}).htmlSafe(); + } +}); diff --git a/app/assets/javascripts/select-kit/components/multi-select/selected-color.js.es6 b/app/assets/javascripts/select-kit/components/multi-select/selected-color.js.es6 new file mode 100644 index 00000000000..3349d95ff8a --- /dev/null +++ b/app/assets/javascripts/select-kit/components/multi-select/selected-color.js.es6 @@ -0,0 +1,11 @@ +import SelectedNameComponent from "select-kit/components/multi-select/selected-name"; + +export default SelectedNameComponent.extend({ + classNames: "selected-color", + layoutName: "select-kit/templates/components/multi-select/selected-color", + + didRender() { + const name = this.get("content.name"); + this.$(".color-preview").css("background", `#${name}`.htmlSafe()); + } +}); diff --git a/app/assets/javascripts/select-box-kit/components/multi-combo-box/selected-name.js.es6 b/app/assets/javascripts/select-kit/components/multi-select/selected-name.js.es6 similarity index 50% rename from app/assets/javascripts/select-box-kit/components/multi-combo-box/selected-name.js.es6 rename to app/assets/javascripts/select-kit/components/multi-select/selected-name.js.es6 index 07c3ad0d64c..c3ca9488e53 100644 --- a/app/assets/javascripts/select-box-kit/components/multi-combo-box/selected-name.js.es6 +++ b/app/assets/javascripts/select-kit/components/multi-select/selected-name.js.es6 @@ -1,18 +1,27 @@ +import computed from "ember-addons/ember-computed-decorators"; + export default Ember.Component.extend({ - attributeBindings: ["tabindex","content.name:data-name", "content.value:data-value"], - classNames: "selected-name", + attributeBindings: [ + "tabindex", + "content.name:data-name", + "content.value:data-value", + "guid:data-guid" + ], + classNames: ["selected-name", "choice"], classNameBindings: ["isHighlighted", "isLocked"], - layoutName: "select-box-kit/templates/components/multi-combo-box/selected-name", + layoutName: "select-kit/templates/components/multi-select/selected-name", tagName: "li", tabindex: -1, + @computed("content") + guid(content) { return Ember.guidFor(content); }, + isLocked: Ember.computed("content.locked", function() { return this.getWithDefault("content.locked", false); }), click() { if (this.get("isLocked") === true) { return false; } - this.toggleProperty("isHighlighted"); return false; } diff --git a/app/assets/javascripts/select-kit/components/none-category-row.js.es6 b/app/assets/javascripts/select-kit/components/none-category-row.js.es6 new file mode 100644 index 00000000000..60b932920ee --- /dev/null +++ b/app/assets/javascripts/select-kit/components/none-category-row.js.es6 @@ -0,0 +1,10 @@ +import CategoryRowComponent from "select-kit/components/category-row"; + +export default CategoryRowComponent.extend({ + layoutName: "select-kit/templates/components/category-row", + classNames: "none category-row", + + click() { + this.sendAction("onClear"); + } +}); diff --git a/app/assets/javascripts/select-box-kit/components/notifications-button.js.es6 b/app/assets/javascripts/select-kit/components/notifications-button.js.es6 similarity index 56% rename from app/assets/javascripts/select-box-kit/components/notifications-button.js.es6 rename to app/assets/javascripts/select-kit/components/notifications-button.js.es6 index d0515535001..344ca204cee 100644 --- a/app/assets/javascripts/select-box-kit/components/notifications-button.js.es6 +++ b/app/assets/javascripts/select-kit/components/notifications-button.js.es6 @@ -1,4 +1,4 @@ -import DropdownSelectBoxComponent from "select-box-kit/components/dropdown-select-box"; +import DropdownSelectBoxComponent from "select-kit/components/dropdown-select-box"; import { default as computed, on } from "ember-addons/ember-computed-decorators"; import { buttonDetails } from "discourse/lib/notification-levels"; import { allLevels } from "discourse/lib/notification-levels"; @@ -9,24 +9,29 @@ export default DropdownSelectBoxComponent.extend({ fullWidthOnMobile: true, content: allLevels, collectionHeight: "auto", - value: Ember.computed.alias("notificationLevel"), castInteger: true, autofilterable: false, filterable: false, rowComponent: "notifications-button/notifications-button-row", - headerComponent: "notifications-button/notifications-button-header", - + allowInitialValueMutation: false, i18nPrefix: "", i18nPostfix: "", - showFullTitle: true, - @on("didReceiveAttrs", "didUpdateAttrs") - _setComponentOptions() { - this.get("headerComponentOptions").setProperties({ - i18nPrefix: this.get("i18nPrefix"), - showFullTitle: this.get("showFullTitle"), - }); + @computed("iconForSelectedDetails") + headerIcon(iconForSelectedDetails) { return iconForSelectedDetails; }, + @computed("selectedDetails.icon") + iconForSelectedDetails(icon) { return icon; }, + + computeHeaderContent() { + let content = this.baseHeaderComputedContent(); + content.name = I18n.t(`${this.get("i18nPrefix")}.${this.get("selectedDetails.key")}.title`); + content.hasSelection = this.get("hasSelection"); + return content; + }, + + @on("didReceiveAttrs") + _setNotificationsButtonComponentOptions() { this.get("rowComponentOptions").setProperties({ i18nPrefix: this.get("i18nPrefix"), i18nPostfix: this.get("i18nPostfix") diff --git a/app/assets/javascripts/select-box-kit/components/notifications-button/notifications-button-row.js.es6 b/app/assets/javascripts/select-kit/components/notifications-button/notifications-button-row.js.es6 similarity index 76% rename from app/assets/javascripts/select-box-kit/components/notifications-button/notifications-button-row.js.es6 rename to app/assets/javascripts/select-kit/components/notifications-button/notifications-button-row.js.es6 index 6f3f257b439..e2e89d3a0b1 100644 --- a/app/assets/javascripts/select-box-kit/components/notifications-button/notifications-button-row.js.es6 +++ b/app/assets/javascripts/select-kit/components/notifications-button/notifications-button-row.js.es6 @@ -1,4 +1,4 @@ -import DropdownSelectBoxRoxComponent from "select-box-kit/components/dropdown-select-box/dropdown-select-box-row"; +import DropdownSelectBoxRoxComponent from "select-kit/components/dropdown-select-box/dropdown-select-box-row"; import { buttonDetails } from "discourse/lib/notification-levels"; import computed from "ember-addons/ember-computed-decorators"; import { iconHTML } from 'discourse-common/lib/icon-library'; @@ -9,13 +9,13 @@ export default DropdownSelectBoxRoxComponent.extend({ i18nPrefix: Ember.computed.alias("options.i18nPrefix"), i18nPostfix: Ember.computed.alias("options.i18nPostfix"), - @computed("content.value", "i18nPrefix") + @computed("computedContent.value", "i18nPrefix") title(value, prefix) { const key = buttonDetails(value).key; return I18n.t(`${prefix}.${key}.title`); }, - @computed("content.name", "content.originalContent.icon") + @computed("computedContent.name", "computedContent.originalContent.icon") icon(contentName, icon) { return iconHTML(icon, { class: contentName.dasherize() }); }, @@ -30,7 +30,7 @@ export default DropdownSelectBoxRoxComponent.extend({ return Handlebars.escapeExpression(I18n.t(`${_start}.title`)); }, - @computed("i18nPrefix", "i18nPostfix", "content.name") + @computed("i18nPrefix", "i18nPostfix", "computedContent.name") _start(prefix, postfix, contentName) { return `${prefix}.${contentName}${postfix}`; }, diff --git a/app/assets/javascripts/select-box-kit/components/pinned-button.js.es6 b/app/assets/javascripts/select-kit/components/pinned-button.js.es6 similarity index 71% rename from app/assets/javascripts/select-box-kit/components/pinned-button.js.es6 rename to app/assets/javascripts/select-kit/components/pinned-button.js.es6 index c36d53c2369..079274a2a8a 100644 --- a/app/assets/javascripts/select-box-kit/components/pinned-button.js.es6 +++ b/app/assets/javascripts/select-kit/components/pinned-button.js.es6 @@ -1,12 +1,13 @@ import computed from "ember-addons/ember-computed-decorators"; export default Ember.Component.extend({ + pluginApiIdentifiers: ["pinned-button"], descriptionKey: "help", classNames: "pinned-button", classNameBindings: ["isHidden"], - layoutName: "select-box-kit/templates/components/pinned-button", + layoutName: "select-kit/templates/components/pinned-button", - @computed("topic.pinned_globally", "topic.pinned") + @computed("topic.pinned_globally", "pinned") reasonText(pinnedGlobally, pinned) { const globally = pinnedGlobally ? "_globally" : ""; const pinnedKey = pinned ? `pinned${globally}` : "unpinned"; @@ -14,7 +15,7 @@ export default Ember.Component.extend({ return I18n.t(key); }, - @computed("topic.pinned", "topic.deleted", "topic.unpinned") + @computed("pinned", "topic.deleted", "topic.unpinned") isHidden(pinned, deleted, unpinned) { return deleted || (!pinned && !unpinned); } diff --git a/app/assets/javascripts/select-kit/components/pinned-options.js.es6 b/app/assets/javascripts/select-kit/components/pinned-options.js.es6 new file mode 100644 index 00000000000..ebf51344327 --- /dev/null +++ b/app/assets/javascripts/select-kit/components/pinned-options.js.es6 @@ -0,0 +1,55 @@ +import DropdownSelectBoxComponent from "select-kit/components/dropdown-select-box"; +import { on } from "ember-addons/ember-computed-decorators"; +import { iconHTML } from 'discourse-common/lib/icon-library'; + +export default DropdownSelectBoxComponent.extend({ + pluginApiIdentifiers: ["pinned-options"], + classNames: "pinned-options", + allowInitialValueMutation: false, + + autoHighlight() {}, + + computeHeaderContent() { + let content = this.baseHeaderComputedContent(); + const pinnedGlobally = this.get("topic.pinned_globally"); + const pinned = this.get("computedValue"); + const globally = pinnedGlobally ? "_globally" : ""; + const state = pinned ? `pinned${globally}` : "unpinned"; + const title = I18n.t(`topic_statuses.${state}.title`); + + content.name = `${title}${iconHTML("caret-down")}`.htmlSafe(); + content.dataName = title; + content.icon = `thumb-tack ${state === "unpinned" ? "unpinned" : null}`; + return content; + }, + + @on("init") + _setContent() { + const globally = this.get("topic.pinned_globally") ? "_globally" : ""; + + this.set("content", [ + { + id: "pinned", + name: I18n.t("topic_statuses.pinned" + globally + ".title"), + description: I18n.t('topic_statuses.pinned' + globally + '.help'), + icon: "thumb-tack" + }, + { + id: "unpinned", + name: I18n.t("topic_statuses.unpinned.title"), + icon: "thumb-tack unpinned", + description: I18n.t('topic_statuses.unpinned.help'), + } + ]); + }, + + mutateValue(value) { + const topic = this.get("topic"); + + if (value === "unpinned") { + topic.clearPin(); + } else { + topic.rePin(); + } + } +}); diff --git a/app/assets/javascripts/select-kit/components/search-advanced-category-chooser.js.es6 b/app/assets/javascripts/select-kit/components/search-advanced-category-chooser.js.es6 new file mode 100644 index 00000000000..6ab1319d416 --- /dev/null +++ b/app/assets/javascripts/select-kit/components/search-advanced-category-chooser.js.es6 @@ -0,0 +1,20 @@ +import CategoryChooserComponent from "select-kit/components/category-chooser"; +import Category from "discourse/models/category"; + +export default CategoryChooserComponent.extend({ + pluginApiIdentifiers: ["advanced-search-category-chooser"], + rootNone: true, + rootNoneLabel: "category.all", + allowUncategorized: true, + clearable: true, + + mutateValue(value) { + if (value) { + this.set("value", Category.findById(value)); + } else { + this.set("value", null); + } + }, + + computeValue(category) { if (category) return category.id; } +}); diff --git a/app/assets/javascripts/select-kit/components/select-kit.js.es6 b/app/assets/javascripts/select-kit/components/select-kit.js.es6 new file mode 100644 index 00000000000..29b418540da --- /dev/null +++ b/app/assets/javascripts/select-kit/components/select-kit.js.es6 @@ -0,0 +1,239 @@ +const { isNone, run, makeArray } = Ember; +import computed from "ember-addons/ember-computed-decorators"; +import UtilsMixin from "select-kit/mixins/utils"; +import DomHelpersMixin from "select-kit/mixins/dom-helpers"; +import EventsMixin from "select-kit/mixins/events"; +import PluginApiMixin from "select-kit/mixins/plugin-api"; +import { applyContentPluginApiCallbacks } from "select-kit/mixins/plugin-api"; + +export default Ember.Component.extend(UtilsMixin, PluginApiMixin, DomHelpersMixin, EventsMixin, { + pluginApiIdentifiers: ["select-kit"], + layoutName: "select-kit/templates/components/select-kit", + classNames: ["select-kit", "select-box-kit"], + classNameBindings: [ + "isFocused", + "isExpanded", + "isDisabled", + "isHidden", + "isAbove", + "isBelow", + "isLeftAligned", + "isRightAligned" + ], + isDisabled: false, + isExpanded: false, + isFocused: false, + isHidden: false, + renderedBodyOnce: false, + renderedFilterOnce: false, + tabindex: 0, + scrollableParentSelector: ".modal-body", + none: null, + highlightedValue: null, + noContentLabel: "select_kit.no_content", + valueAttribute: "id", + nameProperty: "name", + autoFilterable: false, + filterable: false, + filter: "", + filterPlaceholder: "select_kit.filter_placeholder", + filterIcon: "search", + headerIcon: null, + rowComponent: "select-kit/select-kit-row", + rowComponentOptions: null, + noneRowComponent: "select-kit/select-kit-none-row", + createRowComponent: "select-kit/select-kit-create-row", + filterComponent: "select-kit/select-kit-filter", + headerComponent: "select-kit/select-kit-header", + headerComponentOptions: null, + headerComputedContent: null, + collectionComponent: "select-kit/select-kit-collection", + collectionHeight: 200, + verticalOffset: 0, + horizontalOffset: 0, + fullWidthOnMobile: false, + castInteger: false, + allowAny: false, + allowInitialValueMutation: false, + content: null, + computedContent: null, + limitMatches: 100, + + init() { + this._super(); + + this.noneValue = "__none__"; + this._previousScrollParentOverflow = "auto"; + this._previousCSSContext = {}; + this.set("headerComponentOptions", Ember.Object.create()); + this.set("rowComponentOptions", Ember.Object.create()); + this.set("computedContent", []); + + if ($(window).outerWidth(false) <= 420) { + this.setProperties({ filterable: false, autoFilterable: false }); + } + }, + + willComputeAttributes() {}, + didComputeAttributes() {}, + + _beforeWillComputeContent(content) { return makeArray(content); }, + willComputeContent(content) { return content; }, + computeContent(content) { return content; }, + _beforeDidComputeContent(content) { + content = applyContentPluginApiCallbacks(this.get("pluginApiIdentifiers"), content); + + const existingCreatedComputedContent = this.get("computedContent").filterBy("created", true); + this.setProperties({ + computedContent: content.map(c => this.computeContentItem(c)).concat(existingCreatedComputedContent) + }); + return content; + }, + didComputeContent() {}, + + mutateAttributes() { + run.next(() => { + this.mutateContent(this.get("computedContent")); + this.mutateValue(this.get("computedValue")); + this.set("headerComputedContent", this.computeHeaderContent()); + }); + }, + mutateContent() {}, + mutateValue(computedValue) { this.set("value", computedValue); }, + + computeHeaderContent() { + return this.baseHeaderComputedContent(); + }, + + computeContentItem(contentItem, options) { + return this.baseComputedContentItem(contentItem, options); + }, + + baseComputedContentItem(contentItem, options) { + let originalContent; + options = options || {}; + const name = options.name; + + if (typeof contentItem === "string" || typeof contentItem === "number") { + originalContent = {}; + originalContent[this.get("valueAttribute")] = contentItem; + originalContent[this.get("nameProperty")] = name || contentItem; + } else { + originalContent = contentItem; + } + + return { + value: this._castInteger(this.valueForContentItem(contentItem)), + name: name || this._nameForContent(contentItem), + locked: false, + created: options.created || false, + originalContent + }; + }, + + @computed("shouldFilter", "allowAny", "filter") + shouldDisplayFilter(shouldFilter, allowAny, filter) { + if (shouldFilter === true) return true; + if (allowAny === true && filter.length > 0) return true; + return false; + }, + + @computed("filter", "filteredComputedContent.[]") + shouldDisplayNoContentRow(filter, filteredComputedContent) { + return filter.length > 0 && filteredComputedContent.length === 0; + }, + + @computed("filter", "filterable", "autoFilterable", "renderedFilterOnce") + shouldFilter(filter, filterable, autoFilterable, renderedFilterOnce) { + if (renderedFilterOnce === true && filterable === true) return true; + if (filterable === true) return true; + if (autoFilterable === true && filter.length > 0) return true; + return false; + }, + + @computed("filter", "computedContent") + shouldDisplayCreateRow(filter, computedContent) { + if (computedContent.map(c => c.value).includes(filter)) return false; + if (this.get("allowAny") === true && filter.length > 0) return true; + return false; + }, + + @computed("filter", "shouldDisplayCreateRow") + createRowComputedContent(filter, shouldDisplayCreateRow) { + if (shouldDisplayCreateRow === true) { + let content = this.createContentFromInput(filter); + return this.computeContentItem(content, { created: true }); + } + }, + + @computed + templateForRow() { return () => null; }, + + @computed + templateForNoneRow() { return () => null; }, + + @computed("filter") + templateForCreateRow() { + return (rowComponent) => { + return I18n.t("select_box.create", { + content: rowComponent.get("computedContent.name") + }); + }; + }, + + @computed("none") + noneRowComputedContent(none) { + if (isNone(none)) { return null; } + + switch (typeof none) { + case "string": + return this.computeContentItem(this.noneValue, { name: I18n.t(none) }); + default: + return this.computeContentItem(none); + } + }, + + createContentFromInput(input) { return input; }, + + willSelect() { + this.clearFilter(); + this.set("highlightedValue", null); + }, + didSelect() { + this.collapse(); + this.focus(); + }, + + willDeselect() { + this.clearFilter(); + this.set("highlightedValue", null); + }, + didDeselect() { + this.collapse(); + this.focus(); + }, + + clearFilter() { + this.$filterInput().val(""); + this.setProperties({ filter: "" }); + }, + + actions: { + onToggle() { + this.get("isExpanded") === true ? this.collapse() : this.expand(); + }, + + onHighlight(rowComputedContent) { + this.set("highlightedValue", rowComputedContent.value); + }, + + onFilter(filter) { + this.setProperties({ + highlightedValue: null, + renderedFilterOnce: true, + filter + }); + this.autoHighlight(); + } + } +}); diff --git a/app/assets/javascripts/select-kit/components/select-kit/select-kit-collection.js.es6 b/app/assets/javascripts/select-kit/components/select-kit/select-kit-collection.js.es6 new file mode 100644 index 00000000000..67508609d2a --- /dev/null +++ b/app/assets/javascripts/select-kit/components/select-kit/select-kit-collection.js.es6 @@ -0,0 +1,5 @@ +export default Ember.Component.extend({ + layoutName: "select-kit/templates/components/select-kit/select-kit-collection", + classNames: ["select-kit-collection", "select-box-kit-collection"], + tagName: "ul" +}); diff --git a/app/assets/javascripts/select-kit/components/select-kit/select-kit-create-row.js.es6 b/app/assets/javascripts/select-kit/components/select-kit/select-kit-create-row.js.es6 new file mode 100644 index 00000000000..390408349b9 --- /dev/null +++ b/app/assets/javascripts/select-kit/components/select-kit/select-kit-create-row.js.es6 @@ -0,0 +1,10 @@ +import SelectKitRowComponent from "select-kit/components/select-kit/select-kit-row"; + +export default SelectKitRowComponent.extend({ + layoutName: "select-kit/templates/components/select-kit/select-kit-row", + classNames: "create", + + click() { + this.sendAction("onCreate", this.get("computedContent")); + }, +}); diff --git a/app/assets/javascripts/select-box-kit/components/select-box-kit/select-box-kit-filter.js.es6 b/app/assets/javascripts/select-kit/components/select-kit/select-kit-filter.js.es6 similarity index 51% rename from app/assets/javascripts/select-box-kit/components/select-box-kit/select-box-kit-filter.js.es6 rename to app/assets/javascripts/select-kit/components/select-kit/select-kit-filter.js.es6 index aafaa5e1363..f60a627de85 100644 --- a/app/assets/javascripts/select-box-kit/components/select-box-kit/select-box-kit-filter.js.es6 +++ b/app/assets/javascripts/select-kit/components/select-kit/select-kit-filter.js.es6 @@ -1,6 +1,6 @@ export default Ember.Component.extend({ - layoutName: "select-box-kit/templates/components/select-box-kit/select-box-kit-filter", - classNames: "select-box-kit-filter", + layoutName: "select-kit/templates/components/select-kit/select-kit-filter", + classNames: ["select-kit-filter", "select-box-kit-filter"], classNameBindings: ["isFocused", "isHidden"], isHidden: Ember.computed.not("shouldDisplayFilter") }); diff --git a/app/assets/javascripts/select-kit/components/select-kit/select-kit-header.js.es6 b/app/assets/javascripts/select-kit/components/select-kit/select-kit-header.js.es6 new file mode 100644 index 00000000000..30863d179c4 --- /dev/null +++ b/app/assets/javascripts/select-kit/components/select-kit/select-kit-header.js.es6 @@ -0,0 +1,35 @@ +import computed from 'ember-addons/ember-computed-decorators'; + +export default Ember.Component.extend({ + layoutName: "select-kit/templates/components/select-kit/select-kit-header", + classNames: ["select-kit-header", "select-box-kit-header"], + classNameBindings: ["isFocused"], + attributeBindings: [ + "dataName:data-name", + "tabindex", + "ariaLabel:aria-label", + "ariaHasPopup:aria-haspopup", + "title" + ], + + ariaHasPopup: true, + + ariaLabel: Ember.computed.alias("title"), + + name: Ember.computed.alias("computedContent.name"), + + @computed("computedContent.icon", "computedContent.icons") + icons(icon, icons) { + return Ember.makeArray(icon).concat(icons).filter(i => !Ember.isEmpty(i)); + }, + + @computed("computedContent.dataName", "name") + dataName(dataName, name) { return dataName || name; }, + + @computed("computedContent.title", "name") + title(title, name) { return title || name; }, + + click() { + this.sendAction("onToggle"); + } +}); diff --git a/app/assets/javascripts/select-kit/components/select-kit/select-kit-none-row.js.es6 b/app/assets/javascripts/select-kit/components/select-kit/select-kit-none-row.js.es6 new file mode 100644 index 00000000000..542b9472c41 --- /dev/null +++ b/app/assets/javascripts/select-kit/components/select-kit/select-kit-none-row.js.es6 @@ -0,0 +1,10 @@ +import SelectKitRowComponent from "select-kit/components/select-kit/select-kit-row"; + +export default SelectKitRowComponent.extend({ + layoutName: "select-kit/templates/components/select-kit/select-kit-row", + classNames: "none", + + click() { + this.sendAction("onClear"); + } +}); diff --git a/app/assets/javascripts/select-kit/components/select-kit/select-kit-row.js.es6 b/app/assets/javascripts/select-kit/components/select-kit/select-kit-row.js.es6 new file mode 100644 index 00000000000..f9c46b0a1e9 --- /dev/null +++ b/app/assets/javascripts/select-kit/components/select-kit/select-kit-row.js.es6 @@ -0,0 +1,58 @@ +import { on } from 'ember-addons/ember-computed-decorators'; +import computed from 'ember-addons/ember-computed-decorators'; +const { run, isPresent, makeArray, isEmpty } = Ember; +import UtilsMixin from "select-kit/mixins/utils"; + +export default Ember.Component.extend(UtilsMixin, { + layoutName: "select-kit/templates/components/select-kit/select-kit-row", + classNames: ["select-kit-row", "select-box-kit-row"], + tagName: "li", + tabIndex: -1, + attributeBindings: [ + "tabIndex", + "title", + "computedContent.value:data-value", + "computedContent.name:data-name" + ], + classNameBindings: ["isHighlighted", "isSelected"], + + @computed("computedContent.title", "computedContent.name") + title(title, name) { return title || name; }, + + @computed("templateForRow") + template(templateForRow) { return templateForRow(this); }, + + @on("didReceiveAttrs") + _setSelectionState() { + const contentValue = this.get("computedContent.value"); + + this.set("isSelected", this.get("computedValue") === contentValue); + this.set("isHighlighted", this.get("highlightedValue") === contentValue); + }, + + @on("willDestroyElement") + _clearDebounce() { + const hoverDebounce = this.get("hoverDebounce"); + if (isPresent(hoverDebounce)) { run.cancel(hoverDebounce); } + }, + + @computed("computedContent.icon", "computedContent.icons", "computedContent.originalContent.icon") + icons(icon, icons, originalIcon) { + return makeArray(icon) + .concat(icons) + .concat(makeArray(originalIcon)) + .filter(i => !isEmpty(i)); + }, + + mouseEnter() { + this.set("hoverDebounce", run.debounce(this, this._sendOnHighlightAction, 32)); + }, + + click() { + this.sendAction("onSelect", this.get("computedContent")); + }, + + _sendOnHighlightAction() { + this.sendAction("onHighlight", this.get("computedContent")); + } +}); diff --git a/app/assets/javascripts/select-kit/components/single-select.js.es6 b/app/assets/javascripts/select-kit/components/single-select.js.es6 new file mode 100644 index 00000000000..a363b1d67e3 --- /dev/null +++ b/app/assets/javascripts/select-kit/components/single-select.js.es6 @@ -0,0 +1,168 @@ +import SelectKitComponent from "select-kit/components/select-kit"; +import { on } from "ember-addons/ember-computed-decorators"; +import computed from "ember-addons/ember-computed-decorators"; +const { get, isNone, isEmpty, isPresent } = Ember; + +export default SelectKitComponent.extend({ + pluginApiIdentifiers: ["single-select"], + classNames: "single-select", + computedValue: null, + value: null, + allowInitialValueMutation: true, + + init() { + this._super(); + + if (this.get("allowInitialValueMutation") === true) { + const none = isNone(this.get("none")); + const emptyValue = isEmpty(this.get("value")); + if (none && emptyValue) { + if (!isEmpty(this.get("content"))) { + const value = this.valueForContentItem(this.get("content.firstObject")); + Ember.run.next(() => this.mutateValue(value)); + } + } + } + }, + + @on("didReceiveAttrs") + _compute() { + Ember.run.scheduleOnce("afterRender", () => { + this.willComputeAttributes(); + let content = this._beforeWillComputeContent(this.get("content")); + content = this.willComputeContent(content); + let value = this._beforeWillComputeValue(this.get("value")); + content = this.computeContent(content); + content = this._beforeDidComputeContent(content); + value = this.willComputeValue(value); + value = this.computeValue(value); + value = this._beforeDidComputeValue(value); + this.didComputeContent(content); + this.didComputeValue(value); + this.set("headerComputedContent", this.computeHeaderContent()); + this.didComputeAttributes(); + }); + }, + + _beforeWillComputeValue(value) { + switch (typeof value) { + case "string": + case "number": + return this._castInteger(value === "" ? null : value); + default: + return value; + } + }, + willComputeValue(value) { return value; }, + computeValue(value) { return value; }, + _beforeDidComputeValue(value) { + if (!isEmpty(this.get("content")) && isNone(value) && isNone(this.get("none"))) { + value = this.valueForContentItem(get(this.get("content"), "firstObject")); + } + + this.setProperties({ computedValue: value }); + return value; + }, + didComputeValue(value) { return value; }, + + filterComputedContent(computedContent, computedValue, filter) { + const lowerFilter = filter.toLowerCase(); + return computedContent.filter(c => { + return get(c, "name").toLowerCase().indexOf(lowerFilter) > -1; + }); + }, + + baseHeaderComputedContent() { + return { + icons: Ember.makeArray(this.getWithDefault("headerIcon", [])), + name: this.get("selectedComputedContent.name") || this.get("noneRowComputedContent.name") + }; + }, + + @computed("computedContent.[]", "computedValue", "filter", "shouldFilter") + filteredComputedContent(computedContent, computedValue, filter, shouldFilter) { + if (shouldFilter === true) { + computedContent = this.filterComputedContent(computedContent, computedValue, filter); + } + + return computedContent.slice(0, this.get("limitMatches")); + }, + + @computed("computedValue", "computedContent.[]") + selectedComputedContent(computedValue, computedContent) { + if (isNone(computedValue) || isNone(computedContent)) { return null; } + return computedContent.findBy("value", computedValue); + }, + + @computed("selectedComputedContent") + hasSelection(selectedComputedContent) { + return selectedComputedContent !== this.get("noneRowComputedContent") && + !Ember.isNone(selectedComputedContent); + }, + + @computed("filter", "computedValue") + shouldDisplayCreateRow(filter, computedValue) { + return this._super() && computedValue !== filter; + }, + + autoHighlight() { + Ember.run.schedule("afterRender", () => { + if (!isNone(this.get("highlightedValue"))) { return; } + + const filteredComputedContent = this.get("filteredComputedContent"); + const displayCreateRow = this.get("shouldDisplayCreateRow"); + const none = this.get("noneRowComputedContent"); + + if (this.get("hasSelection") && isEmpty(this.get("filter"))) { + this.send("onHighlight", this.get("selectedComputedContent")); + return; + } + + if (isNone(this.get("highlightedValue")) && !isEmpty(filteredComputedContent)) { + this.send("onHighlight", get(filteredComputedContent, "firstObject")); + return; + } + + if (displayCreateRow === true && isEmpty(filteredComputedContent)) { + this.send("onHighlight", this.get("createRowComputedContent")); + } + else if (!isEmpty(filteredComputedContent)) { + this.send("onHighlight", get(filteredComputedContent, "firstObject")); + } + else if (isEmpty(filteredComputedContent) && isPresent(none) && displayCreateRow === false) { + this.send("onHighlight", none); + } + }); + }, + + validateComputedContentItem(computedContentItem) { + return this.get("computedValue") !== computedContentItem.value; + }, + + actions: { + onClear() { + this.send("onDeselect", this.get("selectedComputedContent")); + }, + + onCreate(computedContentItem) { + if (this.validateComputedContentItem(computedContentItem)) { + this.get("computedContent").pushObject(computedContentItem); + this.send("onSelect", computedContentItem); + } + }, + + onSelect(rowComputedContentItem) { + this.willSelect(rowComputedContentItem); + this.set("computedValue", rowComputedContentItem.value); + this.mutateAttributes(); + Ember.run.schedule("afterRender", () => this.didSelect(rowComputedContentItem)); + }, + + onDeselect(rowComputedContentItem) { + this.willDeselect(rowComputedContentItem); + this.set("computedValue", null); + this.mutateAttributes(); + Ember.run.schedule("afterRender", () => this.didDeselect(rowComputedContentItem)); + } + } +}); diff --git a/app/assets/javascripts/select-kit/components/tag-notifications-button.js.es6 b/app/assets/javascripts/select-kit/components/tag-notifications-button.js.es6 new file mode 100644 index 00000000000..7208f8c81ab --- /dev/null +++ b/app/assets/javascripts/select-kit/components/tag-notifications-button.js.es6 @@ -0,0 +1,23 @@ +import NotificationOptionsComponent from "select-kit/components/notifications-button"; +import computed from "ember-addons/ember-computed-decorators"; + +export default NotificationOptionsComponent.extend({ + pluginApiIdentifiers: ["tag-notifications-button"], + classNames: "tag-notifications-button", + i18nPrefix: "tagging.notifications", + showFullTitle: false, + allowInitialValueMutation: false, + + mutateValue(value) { + this.sendAction("action", value); + }, + + computeValue() { + return this.get("notificationLevel"); + }, + + @computed("iconForSelectedDetails") + headerIcon(iconForSelectedDetails) { + return [iconForSelectedDetails, "caret-down"]; + } +}); diff --git a/app/assets/javascripts/select-box-kit/components/topic-footer-mobile-dropdown.js.es6 b/app/assets/javascripts/select-kit/components/topic-footer-mobile-dropdown.js.es6 similarity index 68% rename from app/assets/javascripts/select-box-kit/components/topic-footer-mobile-dropdown.js.es6 rename to app/assets/javascripts/select-kit/components/topic-footer-mobile-dropdown.js.es6 index 2222fbc8221..ccdf3af4890 100644 --- a/app/assets/javascripts/select-box-kit/components/topic-footer-mobile-dropdown.js.es6 +++ b/app/assets/javascripts/select-kit/components/topic-footer-mobile-dropdown.js.es6 @@ -1,24 +1,21 @@ -import computed from "ember-addons/ember-computed-decorators"; -import ComboBoxComponent from "select-box-kit/components/combo-box"; -import { on } from "ember-addons/ember-computed-decorators"; +import ComboBoxComponent from "select-kit/components/combo-box"; export default ComboBoxComponent.extend({ - headerText: "topic.controls", + pluginApiIdentifiers: ["topic-footer-mobile-dropdown"], classNames: "topic-footer-mobile-dropdown", filterable: false, autoFilterable: false, - allowValueMutation: false, - autoSelectFirst: false, + allowInitialValueMutation: false, - @on("didReceiveAttrs") - _setTopicFooterMobileDropdownOptions() { - this.get("headerComponentOptions") - .set("selectedName", I18n.t(this.get("headerText"))); + computeHeaderContent() { + let content = this.baseHeaderComputedContent(); + content.name = I18n.t("topic.controls"); + return content; }, - @computed("topic", "topic.details", "value") - content(topic, details) { - const content = []; + computeContent(content) { + const topic = this.get("topic"); + const details = topic.get("details"); if (details.get("can_invite_to")) { content.push({ id: "invite", icon: "users", name: I18n.t("topic.invite_reply.title") }); @@ -39,16 +36,15 @@ export default ComboBoxComponent.extend({ return content; }, - selectValueFunction(value) { + autoHighlight() {}, + + mutateValue(value) { const topic = this.get("topic"); - // In case it"s not a valid topic if (!topic.get("id")) { return; } - this.set("value", value); - const refresh = () => this.send("onDeselect", value); switch(value) { diff --git a/app/assets/javascripts/select-box-kit/components/topic-notifications-button.js.es6 b/app/assets/javascripts/select-kit/components/topic-notifications-button.js.es6 similarity index 62% rename from app/assets/javascripts/select-box-kit/components/topic-notifications-button.js.es6 rename to app/assets/javascripts/select-kit/components/topic-notifications-button.js.es6 index 3aeb9a9d980..741b89106f2 100644 --- a/app/assets/javascripts/select-box-kit/components/topic-notifications-button.js.es6 +++ b/app/assets/javascripts/select-kit/components/topic-notifications-button.js.es6 @@ -1,5 +1,5 @@ export default Ember.Component.extend({ - layoutName: "select-box-kit/templates/components/topic-notifications-button", + layoutName: "select-kit/templates/components/topic-notifications-button", classNames: "topic-notifications-button", showFullTitle: true, appendReason: true diff --git a/app/assets/javascripts/select-box-kit/components/topic-notifications-options.js.es6 b/app/assets/javascripts/select-kit/components/topic-notifications-options.js.es6 similarity index 79% rename from app/assets/javascripts/select-box-kit/components/topic-notifications-options.js.es6 rename to app/assets/javascripts/select-kit/components/topic-notifications-options.js.es6 index 34f63f4ea5a..4feb3b003f1 100644 --- a/app/assets/javascripts/select-box-kit/components/topic-notifications-options.js.es6 +++ b/app/assets/javascripts/select-kit/components/topic-notifications-options.js.es6 @@ -1,12 +1,13 @@ -import NotificationOptionsComponent from "select-box-kit/components/notifications-button"; +import NotificationOptionsComponent from "select-kit/components/notifications-button"; import { on } from "ember-addons/ember-computed-decorators"; import { topicLevels } from "discourse/lib/notification-levels"; export default NotificationOptionsComponent.extend({ + pluginApiIdentifiers: ["topic-notifications-options"], classNames: "topic-notifications-options", content: topicLevels, i18nPrefix: "topic.notifications", - value: Ember.computed.alias("topic.details.notification_level"), + allowInitialValueMutation: false, @on("didInsertElement") _bindGlobalLevelChanged() { @@ -24,11 +25,9 @@ export default NotificationOptionsComponent.extend({ this.appEvents.off("topic-notifications-button:changed"); }, - selectValueFunction(value) { + mutateValue(value) { if (value !== this.get("value")) { this.get("topic.details").updateNotifications(value); } - - this.set("value", value); } }); diff --git a/app/assets/javascripts/select-box-kit/mixins/dom-helpers.js.es6 b/app/assets/javascripts/select-kit/mixins/dom-helpers.js.es6 similarity index 71% rename from app/assets/javascripts/select-box-kit/mixins/dom-helpers.js.es6 rename to app/assets/javascripts/select-kit/mixins/dom-helpers.js.es6 index a363c546e0c..2a5afbd3e33 100644 --- a/app/assets/javascripts/select-box-kit/mixins/dom-helpers.js.es6 +++ b/app/assets/javascripts/select-kit/mixins/dom-helpers.js.es6 @@ -4,13 +4,12 @@ export default Ember.Mixin.create({ init() { this._super(); - this.offscreenInputSelector = ".select-box-kit-offscreen"; - this.filterInputSelector = ".select-box-kit-filter-input"; - this.rowSelector = ".select-box-kit-row"; - this.collectionSelector = ".select-box-kit-collection"; - this.headerSelector = ".select-box-kit-header"; - this.bodySelector = ".select-box-kit-body"; - this.wrapperSelector = ".select-box-kit-wrapper"; + this.filterInputSelector = ".filter-input"; + this.rowSelector = ".select-kit-row"; + this.collectionSelector = ".select-kit-collection"; + this.headerSelector = ".select-kit-header"; + this.bodySelector = ".select-kit-body"; + this.wrapperSelector = ".select-kit-wrapper"; }, $findRowByValue(value) { return this.$(`${this.rowSelector}[data-value='${value}']`); }, @@ -34,45 +33,50 @@ export default Ember.Mixin.create({ $selectedRow() { return this.$rows().filter(".is-selected"); }, - $offscreenInput() { return this.$(this.offscreenInputSelector); }, - $filterInput() { return this.$(this.filterInputSelector); }, @on("didRender") _ajustPosition() { - $(`.select-box-kit-fixed-placeholder-${this.elementId}`).remove(); + $(`.select-kit-fixed-placeholder-${this.elementId}`).remove(); this.$collection().css("max-height", this.get("collectionHeight")); this._applyFixedPosition(); this._applyDirection(); this._positionWrapper(); }, + @on("didInsertElement") + _setupResizeListener() { + $(window).on("resize.select-kit", () => this.collapse() ); + }, + @on("willDestroyElement") _clearState() { - $(window).off("resize.select-box-kit"); - $(`.select-box-kit-fixed-placeholder-${this.elementId}`).remove(); + $(window).off("resize.select-kit"); + $(`.select-kit-fixed-placeholder-${this.elementId}`).remove(); }, // make sure we don’t propagate a click outside component // to avoid closing a modal containing the component for example - click(event) { this._killEvent(event); }, + click(event) { + this._destroyEvent(event); + }, // use to collapse and remove focus - close() { - this.collapse(); + close(event) { + this.collapse(event); this.setProperties({ isFocused: false }); }, // force the component in a known default state focus() { - Ember.run.schedule("afterRender", () => this.$offscreenInput().select() ); + Ember.run.schedule("afterRender", () => this.$header().focus() ); }, - expand() { - if (this.get("isExpanded") === true) { return; } + expand(event) { + if (this.get("isExpanded") === true) return; this.setProperties({ isExpanded: true, renderedBodyOnce: true, isFocused: true }); - this.focus(); - this.autoHighlightFunction(); + this.focus(event); + this.autoHighlight(); }, collapse() { @@ -80,35 +84,18 @@ export default Ember.Mixin.create({ Ember.run.schedule("afterRender", () => this._removeFixedPosition() ); }, - // make sure we close/unfocus the component when clicked outside - clickOutside(event) { - if ($(event.target).parents(".select-box-kit").length === 1) { - this.close(); - return false; - } - - this.unfocus(); - return; - }, - // lose focus of the component in two steps - // first collapase and keep focus and then remove focus - unfocus() { - this.set("highlightedValue", null); - + // first collapse and keep focus and then remove focus + unfocus(event) { if (this.get("isExpanded") === true) { - this.collapse(); - this.focus(); + this.collapse(event); + this.focus(event); } else { - this.close(); + this.close(event); } }, - blur() { - Ember.run.schedule("afterRender", () => this.$offscreenInput().blur() ); - }, - - _killEvent(event) { + _destroyEvent(event) { event.preventDefault(); event.stopPropagation(); }, @@ -119,8 +106,8 @@ export default Ember.Mixin.create({ const dHeader = $(".d-header")[0]; const dHeaderBounds = dHeader ? dHeader.getBoundingClientRect() : {top: 0, height: 0}; const dHeaderHeight = dHeaderBounds.top + dHeaderBounds.height; - const headerHeight = this.$header().outerHeight(false); - const headerWidth = this.$header().outerWidth(false); + const componentHeight = this.$().outerHeight(false); + const componentWidth = this.$().outerWidth(false); const bodyHeight = this.$body().outerHeight(false); const windowWidth = $(window).width(); const windowHeight = $(window).height(); @@ -145,7 +132,7 @@ export default Ember.Mixin.create({ options.left = bodyWidth + this.get("horizontalOffset"); } else { this.setProperties({ isLeftAligned: false, isRightAligned: true }); - options.right = - (bodyWidth - headerWidth + this.get("horizontalOffset")); + options.right = - (bodyWidth - componentWidth + this.get("horizontalOffset")); } } else { const horizontalSpacing = boundingRect.left; @@ -160,15 +147,15 @@ export default Ember.Mixin.create({ } } - const componentHeight = this.get("verticalOffset") + bodyHeight + headerHeight; - const hasBelowSpace = windowHeight - offsetBottom - componentHeight > 0; - const hasAboveSpace = offsetTop - componentHeight - dHeaderHeight > 0; + const fullHeight = this.get("verticalOffset") + bodyHeight + componentHeight; + const hasBelowSpace = windowHeight - offsetBottom - fullHeight > 0; + const hasAboveSpace = offsetTop - fullHeight - dHeaderHeight > 0; if (hasBelowSpace || (!hasBelowSpace && !hasAboveSpace)) { this.setProperties({ isBelow: true, isAbove: false }); - options.top = headerHeight + this.get("verticalOffset"); + options.top = componentHeight + this.get("verticalOffset") - 2; } else { this.setProperties({ isBelow: false, isAbove: true }); - options.bottom = headerHeight + this.get("verticalOffset"); + options.bottom = componentHeight + this.get("verticalOffset") - 1; } this.$body().css(options); @@ -182,7 +169,7 @@ export default Ember.Mixin.create({ const width = this.$().outerWidth(false); const height = this.$().outerHeight(false); - const $placeholder = $(`
`); + const $placeholder = $(`
`); this._previousScrollParentOverflow = this._previousScrollParentOverflow || scrollableParent.css("overflow"); scrollableParent.css({ overflow: "hidden" }); @@ -212,7 +199,7 @@ export default Ember.Mixin.create({ }, _removeFixedPosition() { - $(`.select-box-kit-fixed-placeholder-${this.elementId}`).remove(); + $(`.select-kit-fixed-placeholder-${this.elementId}`).remove(); if (!this.element || this.isDestroying || this.isDestroyed) { return; } @@ -236,11 +223,11 @@ export default Ember.Mixin.create({ }, _positionWrapper() { - const headerHeight = this.$header().outerHeight(false); + const componentHeight = this.$().outerHeight(false); this.$(this.wrapperSelector).css({ - width: this.$().outerWidth(false), - height: headerHeight + this.$body().outerHeight(false) + width: this.$().outerWidth(false) - 2, + height: componentHeight + this.$body().outerHeight(false) }); }, }); diff --git a/app/assets/javascripts/select-kit/mixins/events.js.es6 b/app/assets/javascripts/select-kit/mixins/events.js.es6 new file mode 100644 index 00000000000..a462ed683f9 --- /dev/null +++ b/app/assets/javascripts/select-kit/mixins/events.js.es6 @@ -0,0 +1,233 @@ +export default Ember.Mixin.create({ + init() { + this._super(); + + this.keys = { + TAB: 9, + ENTER: 13, + ESC: 27, + UP: 38, + DOWN: 40, + BACKSPACE: 8, + }; + }, + + willDestroyElement() { + this._super(); + + $(document) + .off("mousedown.select-kit") + .off("touchstart.select-kit"); + + this.$header() + .off("focus.select-kit") + .off("blur.select-kit") + .off("keypress.select-kit") + .off("keydown.select-kit"); + + this.$filterInput() + .off("change.select-kit") + .off("keydown.select-kit") + .off("focus.select-kit") + .off("focusin.select-kit"); + }, + + didInsertElement() { + this._super(); + + $(document) + .on("mousedown.select-kit, touchstart.select-kit", event => { + if (Ember.isNone(this.get("element"))) return; + if (this.get("element").contains(event.target)) return; + + this.didClickOutside(event); + }); + + this.$header() + .on("blur.select-kit", () => { + if (this.get("isExpanded") === false && this.get("isFocused") === true) { + this.close(); + } + }) + .on("focus.select-kit", (event) => { + this.set("isFocused", true); + this._destroyEvent(event); + }) + .on("keydown.select-kit", (event) => { + const keyCode = event.keyCode || event.which; + + if (document.activeElement !== this.$header()[0]) return event; + + if (keyCode === this.keys.TAB) this.tabFromHeader(event); + if (keyCode === this.keys.BACKSPACE) this.backspaceFromHeader(event); + if (keyCode === this.keys.ESC) this.escapeFromHeader(event); + if (keyCode === this.keys.ENTER) this.enterFromHeader(event); + if ([this.keys.UP, this.keys.DOWN].includes(keyCode)) this.upAndDownFromHeader(event); + return event; + }) + .on("keypress.select-kit", (event) => { + const keyCode = event.keyCode || event.which; + + if (keyCode === this.keys.ENTER) { return true; } + + this.expand(event); + + if (this.get("filterable") === true || this.get("autoFilterable")) { + this.set("renderedFilterOnce", true); + } + + Ember.run.schedule("afterRender", () => { + let newVal = this.$filterInput().val(); + + const start = this.$filterInput()[0].selectionStart; + const end = this.$filterInput()[0].selectionEnd; + if (!Ember.isNone(start) && !Ember.isNone(end)) { + newVal = newVal.substr(0, start) + + String.fromCharCode(keyCode) + + newVal.substr(end, newVal.length); + } else { + newVal = newVal + String.fromCharCode(keyCode); + } + + this.$filterInput().focus().val(newVal); + }); + + return false; + }); + + this.$filterInput() + .on("change.select-kit", (event) => { + this.send("onFilter", $(event.target).val()); + }) + .on("focus.select-kit focusin.select-kit", (event) => { + this.set("isFocused", true); + this._destroyEvent(event); + }) + .on("keydown.select-kit", (event) => { + const keyCode = event.keyCode || event.which; + + if (keyCode === this.keys.TAB) this.tabFromFilter(event); + if (keyCode === this.keys.ESC) this.escapeFromFilter(event); + if (keyCode === this.keys.ENTER) this.enterFromFilter(event); + if ([this.keys.UP, this.keys.DOWN].includes(keyCode)) this.upAndDownFromFilter(event); + }); + }, + + didPressTab(event) { + if (this.get("isExpanded") === false) { + this.unfocus(event); + } else if (this.$highlightedRow().length === 1) { + this._destroyEvent(event); + Ember.run.throttle(this, this._rowClick, this.$highlightedRow(), 150, 150, true); + this.focus(event); + } else { + this._destroyEvent(event); + this.unfocus(event); + } + + return true; + }, + + didPressEscape(event) { + this._destroyEvent(event); + this.unfocus(event); + }, + + didPressUpAndDownArrows(event) { + this._destroyEvent(event); + + const keyCode = event.keyCode || event.which; + const $rows = this.$rows(); + + if (this.get("isExpanded") === false) { + this.expand(event); + + if (this.$selectedRow().length === 1) { + this._highlightRow(this.$selectedRow()); + return; + } + } + + if ($rows.length <= 0) { return; } + if ($rows.length === 1) { + this._rowSelection($rows, 0); + return; + } + + const direction = keyCode === 38 ? -1 : 1; + + Ember.run.throttle(this, this._moveHighlight, direction, $rows, 32); + }, + + didPressBackspace(event) { + this._destroyEvent(event); + + this.expand(event); + + if (this.$filterInput().is(":visible")) { + this.$filterInput().focus().trigger(event).trigger("change"); + } + }, + + didPressEnter(event) { + this._destroyEvent(event); + + if (this.get("isExpanded") === false) { + this.expand(event); + } else if (this.$highlightedRow().length === 1) { + Ember.run.throttle(this, this._rowClick, this.$highlightedRow(), 150, true); + } + }, + + didClickOutside(event) { + if ($(event.target).parents(".select-kit").length === 1) { + this.close(event); + return false; + } + + this.unfocus(event); + return; + }, + + tabFromHeader(event) { this.didPressTab(event); }, + tabFromFilter(event) { this.didPressTab(event); }, + + escapeFromHeader(event) { this.didPressEscape(event); }, + escapeFromFilter(event) { this.didPressEscape(event); }, + + upAndDownFromHeader(event) { this.didPressUpAndDownArrows(event); }, + upAndDownFromFilter(event) { this.didPressUpAndDownArrows(event); }, + + backspaceFromHeader(event) { this.didPressBackspace(event); }, + + enterFromHeader(event) { this.didPressEnter(event); }, + enterFromFilter(event) { this.didPressEnter(event); }, + + _moveHighlight(direction, $rows) { + const currentIndex = $rows.index(this.$highlightedRow()); + let nextIndex = currentIndex + direction; + + if (nextIndex < 0) { + nextIndex = $rows.length - 1; + } else if (nextIndex >= $rows.length) { + nextIndex = 0; + } + + this._rowSelection($rows, nextIndex); + }, + + _rowClick($row) { $row.click(); }, + + _rowSelection($rows, nextIndex) { + const highlightableValue = $rows.eq(nextIndex).attr("data-value"); + const $highlightableRow = this.$findRowByValue(highlightableValue); + this._highlightRow($highlightableRow); + }, + + _highlightRow($row) { + Ember.run.schedule("afterRender", () => { + $row.trigger("mouseover").focus(); + this.focus(); + }); + } +}); diff --git a/app/assets/javascripts/select-kit/mixins/plugin-api.js.es6 b/app/assets/javascripts/select-kit/mixins/plugin-api.js.es6 new file mode 100644 index 00000000000..effe298a02a --- /dev/null +++ b/app/assets/javascripts/select-kit/mixins/plugin-api.js.es6 @@ -0,0 +1,71 @@ +let _appendContentCallbacks = {}; +function appendContent(pluginApiIdentifiers, contentFunction) { + if (Ember.isNone(_appendContentCallbacks[pluginApiIdentifiers])) { + _appendContentCallbacks[pluginApiIdentifiers] = []; + } + + _appendContentCallbacks[pluginApiIdentifiers].push(contentFunction); +} + +let _prependContentCallbacks = {}; +function prependContent(pluginApiIdentifiers, contentFunction) { + if (Ember.isNone(_prependContentCallbacks[pluginApiIdentifiers])) { + _prependContentCallbacks[pluginApiIdentifiers] = []; + } + + _prependContentCallbacks[pluginApiIdentifiers].push(contentFunction); +} + +let _modifyContentCallbacks = {}; +function modifyContent(pluginApiIdentifiers, contentFunction) { + if (Ember.isNone(_modifyContentCallbacks[pluginApiIdentifiers])) { + _modifyContentCallbacks[pluginApiIdentifiers] = []; + } + + _modifyContentCallbacks[pluginApiIdentifiers].push(contentFunction); +} + +export function applyContentPluginApiCallbacks(identifiers, content) { + identifiers.forEach((key) => { + (_prependContentCallbacks[key] || []).forEach((c) => { + content = c().concat(content); + }); + (_appendContentCallbacks[key] || []).forEach((c) => { + content = content.concat(c()); + }); + (_modifyContentCallbacks[key] || []).forEach((c) => { + content = c(content); + }); + }); + + return content; +} + +export function modifySelectKit(pluginApiIdentifiers) { + return { + appendContent: (content) => { + appendContent(pluginApiIdentifiers, () => {return content;} ); + return modifySelectKit(pluginApiIdentifiers); + }, + prependContent: (content) => { + prependContent(pluginApiIdentifiers, () => {return content;} ); + return modifySelectKit(pluginApiIdentifiers); + }, + modifyContent: (callback) => { + modifyContent(pluginApiIdentifiers, callback); + return modifySelectKit(pluginApiIdentifiers); + } + }; +} + +export function clearCallbacks() { + _appendContentCallbacks = {}; + _prependContentCallbacks = {}; + _modifyContentCallbacks = {}; +} + +const EMPTY_ARRAY = Object.freeze([]); +export default Ember.Mixin.create({ + concatenatedProperties: ["pluginApiIdentifiers"], + pluginApiIdentifiers: EMPTY_ARRAY +}); diff --git a/app/assets/javascripts/select-box-kit/mixins/utils.js.es6 b/app/assets/javascripts/select-kit/mixins/utils.js.es6 similarity index 52% rename from app/assets/javascripts/select-box-kit/mixins/utils.js.es6 rename to app/assets/javascripts/select-kit/mixins/utils.js.es6 index 475cf726fcc..b3ca2dbfedf 100644 --- a/app/assets/javascripts/select-box-kit/mixins/utils.js.es6 +++ b/app/assets/javascripts/select-kit/mixins/utils.js.es6 @@ -1,6 +1,16 @@ -const { get, isNone } = Ember; +const { get, isNone, guidFor } = Ember; export default Ember.Mixin.create({ + valueForContentItem(content) { + switch (typeof content) { + case "string": + case "number": + return content; + default: + return get(content, this.get("valueAttribute")); + } + }, + _nameForContent(content) { if (isNone(content)) { return null; @@ -25,37 +35,13 @@ export default Ember.Mixin.create({ return value; }, - _valueForContent(content) { - switch (typeof content) { - case "string": - case "number": - return content; - default: - return get(content, this.get("valueAttribute")); - } - }, - - _contentForValue(value) { - return this.get("content").find(c => { - if (this._valueForContent(c) === value) { return true; } - }); - }, - - _computedContentForValue(value) { - const searchedValue = value.toString(); + _findComputedContentItemByGuid(guid) { return this.get("computedContent").find(c => { - if (c.value.toString() === searchedValue) { return true; } + return guidFor(c) === guid; }); }, - _originalValueForValue(value) { - if (isNone(value)) { return null; } - if (value === this.noneValue) { return this.noneValue; } - - const computedContent = this._computedContentForValue(value); - - if (isNone(computedContent)) { return value; } - - return get(computedContent.originalContent, this.get("valueAttribute")); - }, + _filterRemovableComputedContents(computedContent) { + return computedContent.filter(c => c.created === true); + } }); diff --git a/app/assets/javascripts/select-kit/templates/components/category-row.hbs b/app/assets/javascripts/select-kit/templates/components/category-row.hbs new file mode 100644 index 00000000000..2ba26d02130 --- /dev/null +++ b/app/assets/javascripts/select-kit/templates/components/category-row.hbs @@ -0,0 +1,19 @@ +{{#if category}} + {{#if hasParentCategory}} +
+ {{badgeForParentCategory}} {{badgeForCategory}} +  × {{topicCount}} +
+ {{else}} +
+ {{badgeForCategory}} +  × {{topicCount}} +
+ {{/if}} + + {{#if hasDescription}} +
{{description}}
+ {{/if}} +{{else}} + {{computedContent.name}} +{{/if}} diff --git a/app/assets/javascripts/select-kit/templates/components/combo-box/combo-box-header.hbs b/app/assets/javascripts/select-kit/templates/components/combo-box/combo-box-header.hbs new file mode 100644 index 00000000000..adc9440ce54 --- /dev/null +++ b/app/assets/javascripts/select-kit/templates/components/combo-box/combo-box-header.hbs @@ -0,0 +1,13 @@ +{{#each icons as |icon|}} {{d-icon icon}} {{/each}} + + + {{{name}}} + + +{{#if shouldDisplayClearableButton}} + +{{/if}} + +{{d-icon caretIcon class="caret-icon"}} diff --git a/app/assets/javascripts/select-kit/templates/components/dropdown-select-box/dropdown-select-box-header.hbs b/app/assets/javascripts/select-kit/templates/components/dropdown-select-box/dropdown-select-box-header.hbs new file mode 100644 index 00000000000..9cc8c31cf60 --- /dev/null +++ b/app/assets/javascripts/select-kit/templates/components/dropdown-select-box/dropdown-select-box-header.hbs @@ -0,0 +1,7 @@ +{{#each icons as |icon|}} {{d-icon icon}} {{/each}} + +{{#if options.showFullTitle}} + + {{name}} + +{{/if}} diff --git a/app/assets/javascripts/select-box-kit/templates/components/dropdown-select-box/dropdown-select-box-row.hbs b/app/assets/javascripts/select-kit/templates/components/dropdown-select-box/dropdown-select-box-row.hbs similarity index 78% rename from app/assets/javascripts/select-box-kit/templates/components/dropdown-select-box/dropdown-select-box-row.hbs rename to app/assets/javascripts/select-kit/templates/components/dropdown-select-box/dropdown-select-box-row.hbs index 0fe1813c8a6..556551a61f0 100644 --- a/app/assets/javascripts/select-box-kit/templates/components/dropdown-select-box/dropdown-select-box-row.hbs +++ b/app/assets/javascripts/select-kit/templates/components/dropdown-select-box/dropdown-select-box-row.hbs @@ -1,10 +1,10 @@ {{#if template}} {{{template}}} {{else}} - {{#if icon}} + {{#if icons}}
- {{{icon}}} + {{#each icons as |icon|}} {{d-icon icon}} {{/each}}
{{/if}} diff --git a/app/assets/javascripts/select-box-kit/templates/components/future-date-input-selector/future-date-input-selector-header.hbs b/app/assets/javascripts/select-kit/templates/components/future-date-input-selector/future-date-input-selector-header.hbs similarity index 51% rename from app/assets/javascripts/select-box-kit/templates/components/future-date-input-selector/future-date-input-selector-header.hbs rename to app/assets/javascripts/select-kit/templates/components/future-date-input-selector/future-date-input-selector-header.hbs index 5e175c5ee7d..4c8904e9a32 100644 --- a/app/assets/javascripts/select-box-kit/templates/components/future-date-input-selector/future-date-input-selector-header.hbs +++ b/app/assets/javascripts/select-kit/templates/components/future-date-input-selector/future-date-input-selector-header.hbs @@ -1,21 +1,21 @@ -{{#if icon}} +{{#if icons}}
- {{{icon}}} + {{#each icons as |icon|}} {{d-icon icon}} {{/each}}
{{/if}} - - {{{selectedName}}} + + {{{name}}} -{{#if datetime}} +{{#if computedContent.datetime}} - {{datetime}} + {{computedContent.datetime}} {{/if}} {{#if shouldDisplayClearableButton}} - {{/if}} diff --git a/app/assets/javascripts/select-box-kit/templates/components/future-date-input-selector/future-date-input-selector-row.hbs b/app/assets/javascripts/select-kit/templates/components/future-date-input-selector/future-date-input-selector-row.hbs similarity index 58% rename from app/assets/javascripts/select-box-kit/templates/components/future-date-input-selector/future-date-input-selector-row.hbs rename to app/assets/javascripts/select-kit/templates/components/future-date-input-selector/future-date-input-selector-row.hbs index dc936cbe690..ce47ece0222 100644 --- a/app/assets/javascripts/select-box-kit/templates/components/future-date-input-selector/future-date-input-selector-row.hbs +++ b/app/assets/javascripts/select-kit/templates/components/future-date-input-selector/future-date-input-selector-row.hbs @@ -1,10 +1,10 @@ -{{#if icon}} +{{#if icons}}
- {{{icon}}} + {{#each icons as |icon|}} {{d-icon icon}} {{/each}}
{{/if}} -{{content.name}} +{{computedContent.name}} {{#if datetime}} diff --git a/app/assets/javascripts/select-kit/templates/components/multi-select/multi-select-header.hbs b/app/assets/javascripts/select-kit/templates/components/multi-select/multi-select-header.hbs new file mode 100644 index 00000000000..8b141c5b3be --- /dev/null +++ b/app/assets/javascripts/select-kit/templates/components/multi-select/multi-select-header.hbs @@ -0,0 +1,13 @@ +
    + {{#each computedContent.selectedComputedContents as |selectedComputedContent|}} + {{component selectedNameComponent onDeselect=onDeselect content=selectedComputedContent}} + {{/each}} +
  • + {{component "select-kit/select-kit-filter" + onFilter=onFilter + shouldDisplayFilter=shouldDisplayFilter + isFocused=isFocused + filter=filter + }} +
  • +
diff --git a/app/assets/javascripts/select-kit/templates/components/multi-select/selected-category.hbs b/app/assets/javascripts/select-kit/templates/components/multi-select/selected-category.hbs new file mode 100644 index 00000000000..c220d68cfc3 --- /dev/null +++ b/app/assets/javascripts/select-kit/templates/components/multi-select/selected-category.hbs @@ -0,0 +1,7 @@ + + + {{d-icon "times"}} + + + {{badge}} + diff --git a/app/assets/javascripts/select-kit/templates/components/multi-select/selected-color.hbs b/app/assets/javascripts/select-kit/templates/components/multi-select/selected-color.hbs new file mode 100644 index 00000000000..c0d544ab9d5 --- /dev/null +++ b/app/assets/javascripts/select-kit/templates/components/multi-select/selected-color.hbs @@ -0,0 +1,13 @@ +
+ + {{#unless isLocked}} + + {{d-icon "times"}} + + {{/unless}} + + #{{content.name}} + + + +
diff --git a/app/assets/javascripts/select-kit/templates/components/multi-select/selected-name.hbs b/app/assets/javascripts/select-kit/templates/components/multi-select/selected-name.hbs new file mode 100644 index 00000000000..67c7a1235a9 --- /dev/null +++ b/app/assets/javascripts/select-kit/templates/components/multi-select/selected-name.hbs @@ -0,0 +1,13 @@ + + {{#if isLocked}} + + {{d-icon "lock"}} + + {{else}} + + {{d-icon "times"}} + + {{/if}} + + {{content.name}} + diff --git a/app/assets/javascripts/select-box-kit/templates/components/pinned-button.hbs b/app/assets/javascripts/select-kit/templates/components/pinned-button.hbs similarity index 50% rename from app/assets/javascripts/select-box-kit/templates/components/pinned-button.hbs rename to app/assets/javascripts/select-kit/templates/components/pinned-button.hbs index aaabc2f1bf3..31fc07f1dcb 100644 --- a/app/assets/javascripts/select-box-kit/templates/components/pinned-button.hbs +++ b/app/assets/javascripts/select-kit/templates/components/pinned-button.hbs @@ -1,4 +1,4 @@ -{{pinned-options topic=topic}} +{{pinned-options value=pinned topic=topic}}

{{{reasonText}}} diff --git a/app/assets/javascripts/select-box-kit/templates/components/select-box-kit.hbs b/app/assets/javascripts/select-kit/templates/components/select-kit.hbs similarity index 56% rename from app/assets/javascripts/select-box-kit/templates/components/select-box-kit.hbs rename to app/assets/javascripts/select-kit/templates/components/select-kit.hbs index 9c9e7188ad7..d15ba708afa 100644 --- a/app/assets/javascripts/select-box-kit/templates/components/select-box-kit.hbs +++ b/app/assets/javascripts/select-kit/templates/components/select-kit.hbs @@ -1,31 +1,19 @@ - - {{component headerComponent - none=computedNone + tabindex=tabindex isFocused=isFocused isExpanded=isExpanded - selectedContent=selectedContent + computedContent=headerComputedContent onDeselect=(action "onDeselect") onToggle=(action "onToggle") - onFilterChange=(action "onFilterChange") - onClearSelection=(action "onClearSelection") - shouldDisplayFilter=shouldDisplayFilter + onFilter=(action "onFilter") + onClear=(action "onClear") options=headerComponentOptions + shouldDisplayFilter=shouldDisplayFilter }} -

+
{{component filterComponent - onFilterChange=(action "onFilterChange") + onFilter=(action "onFilter") icon=filterIcon shouldDisplayFilter=shouldDisplayFilter isFocused=isFocused @@ -35,26 +23,27 @@ {{#if renderedBodyOnce}} {{component collectionComponent - none=computedNone - createRowContent=createRowContent - selectedContent=selectedContent - filteredContent=filteredContent + hasSelection=hasSelection + noneRowComputedContent=noneRowComputedContent + createRowComputedContent=createRowComputedContent + filteredComputedContent=filteredComputedContent rowComponent=rowComponent noneRowComponent=noneRowComponent createRowComponent=createRowComponent templateForRow=templateForRow templateForNoneRow=templateForNoneRow templateForCreateRow=templateForCreateRow - onClearSelection=(action "onClearSelection") + onClear=(action "onClear") onSelect=(action "onSelect") onHighlight=(action "onHighlight") - onCreateContent=(action "onCreateContent") + onCreate=(action "onCreate") noContentLabel=noContentLabel highlightedValue=highlightedValue computedValue=computedValue + shouldDisplayNoContentRow=shouldDisplayNoContentRow rowComponentOptions=rowComponentOptions }} {{/if}}
-
+
diff --git a/app/assets/javascripts/select-box-kit/templates/components/select-box-kit/select-box-kit-collection.hbs b/app/assets/javascripts/select-kit/templates/components/select-kit/select-kit-collection.hbs similarity index 62% rename from app/assets/javascripts/select-box-kit/templates/components/select-box-kit/select-box-kit-collection.hbs rename to app/assets/javascripts/select-kit/templates/components/select-kit/select-kit-collection.hbs index bf7311049cb..824f34f2c1f 100644 --- a/app/assets/javascripts/select-box-kit/templates/components/select-box-kit/select-box-kit-collection.hbs +++ b/app/assets/javascripts/select-kit/templates/components/select-kit/select-kit-collection.hbs @@ -1,10 +1,10 @@ -{{#if none}} - {{#if selectedContent}} +{{#if hasSelection}} + {{#if noneRowComputedContent}} {{component noneRowComponent - content=none + computedContent=noneRowComputedContent templateForRow=templateForNoneRow highlightedValue=highlightedValue - onClearSelection=onClearSelection + onClear=onClear onHighlight=onHighlight value=computedValue options=rowComponentOptions @@ -12,34 +12,34 @@ {{/if}} {{/if}} -{{#if createRowContent}} +{{#if createRowComputedContent}} {{component createRowComponent - content=createRowContent + computedContent=createRowComputedContent templateForRow=templateForCreateRow - titleForRow=titleForRow highlightedValue=highlightedValue onHighlight=onHighlight - onCreateContent=onCreateContent + onCreate=onCreate value=computedValue options=rowComponentOptions }} {{/if}} -{{#each filteredContent as |content|}} +{{#each filteredComputedContent as |computedContent|}} {{component rowComponent - content=content + computedContent=computedContent templateForRow=templateForRow - titleForRow=titleForRow highlightedValue=highlightedValue onSelect=onSelect onHighlight=onHighlight - value=computedValue + computedValue=computedValue options=rowComponentOptions }} -{{else}} +{{/each}} + +{{#if shouldDisplayNoContentRow}} {{#if noContentLabel}} -
  • +
  • {{i18n noContentLabel}}
  • {{/if}} -{{/each}} +{{/if}} diff --git a/app/assets/javascripts/select-box-kit/templates/components/select-box-kit/select-box-kit-filter.hbs b/app/assets/javascripts/select-kit/templates/components/select-kit/select-kit-filter.hbs similarity index 77% rename from app/assets/javascripts/select-box-kit/templates/components/select-box-kit/select-box-kit-filter.hbs rename to app/assets/javascripts/select-kit/templates/components/select-kit/select-kit-filter.hbs index dc50d225040..dd62fca94ad 100644 --- a/app/assets/javascripts/select-box-kit/templates/components/select-box-kit/select-box-kit-filter.hbs +++ b/app/assets/javascripts/select-kit/templates/components/select-kit/select-kit-filter.hbs @@ -1,8 +1,8 @@ {{input tabindex=-1 - class="select-box-kit-filter-input" + class="filter-input" placeholder=placeholder - key-up=onFilterChange + key-up=onFilter autocomplete="off" autocorrect="off" autocapitalize="off" diff --git a/app/assets/javascripts/select-kit/templates/components/select-kit/select-kit-header.hbs b/app/assets/javascripts/select-kit/templates/components/select-kit/select-kit-header.hbs new file mode 100644 index 00000000000..abd119afda2 --- /dev/null +++ b/app/assets/javascripts/select-kit/templates/components/select-kit/select-kit-header.hbs @@ -0,0 +1,5 @@ +{{#each icons as |icon|}} {{d-icon icon}} {{/each}} + + + {{{name}}} + diff --git a/app/assets/javascripts/select-kit/templates/components/select-kit/select-kit-row.hbs b/app/assets/javascripts/select-kit/templates/components/select-kit/select-kit-row.hbs new file mode 100644 index 00000000000..80444173f40 --- /dev/null +++ b/app/assets/javascripts/select-kit/templates/components/select-kit/select-kit-row.hbs @@ -0,0 +1,6 @@ +{{#if template}} + {{{template}}} +{{else}} + {{#each icons as |icon|}} {{d-icon icon}} {{/each}} + {{computedContent.name}} +{{/if}} diff --git a/app/assets/javascripts/select-box-kit/templates/components/topic-notifications-button.hbs b/app/assets/javascripts/select-kit/templates/components/topic-notifications-button.hbs similarity index 50% rename from app/assets/javascripts/select-box-kit/templates/components/topic-notifications-button.hbs rename to app/assets/javascripts/select-kit/templates/components/topic-notifications-button.hbs index 17d99530559..2569ea0c865 100644 --- a/app/assets/javascripts/select-box-kit/templates/components/topic-notifications-button.hbs +++ b/app/assets/javascripts/select-kit/templates/components/topic-notifications-button.hbs @@ -1,4 +1,7 @@ -{{topic-notifications-options topic=topic showFullTitle=showFullTitle}} +{{topic-notifications-options + value=notificationLevel + topic=topic + showFullTitle=showFullTitle}} {{#if appendReason}}

    diff --git a/app/assets/javascripts/wizard-application.js b/app/assets/javascripts/wizard-application.js index 9baf2c224ba..ef619973510 100644 --- a/app/assets/javascripts/wizard-application.js +++ b/app/assets/javascripts/wizard-application.js @@ -3,7 +3,7 @@ //= require ./ember-addons/macro-alias //= require ./ember-addons/ember-computed-decorators //= require_tree ./discourse-common -//= require_tree ./select-box-kit +//= require_tree ./select-kit //= require wizard/router //= require wizard/wizard //= require_tree ./wizard/templates diff --git a/app/assets/javascripts/wizard/test/acceptance/wizard-test.js.es6 b/app/assets/javascripts/wizard/test/acceptance/wizard-test.js.es6 index 3154e426ab1..97029c5eeb0 100644 --- a/app/assets/javascripts/wizard/test/acceptance/wizard-test.js.es6 +++ b/app/assets/javascripts/wizard/test/acceptance/wizard-test.js.es6 @@ -56,7 +56,7 @@ test("Going back and forth in steps", assert => { assert.ok(!exists('.wizard-step-title')); assert.ok(!exists('.wizard-step-description')); - assert.ok(exists('.select-box-kit.field-snack'), "went to the next step"); + assert.ok(exists('.select-kit.field-snack'), "went to the next step"); assert.ok(exists('.preview-area'), "renders the component field"); assert.ok(!exists('.wizard-btn.next')); diff --git a/app/assets/stylesheets/common.scss b/app/assets/stylesheets/common.scss index b4d00edc0c9..565e4317447 100644 --- a/app/assets/stylesheets/common.scss +++ b/app/assets/stylesheets/common.scss @@ -6,7 +6,7 @@ @import "vendor/select2"; @import "common/foundation/mixins"; @import "common/foundation/variables"; -@import "common/select-box-kit/*"; +@import "common/select-kit/*"; @import "common/components/*"; @import "common/input_tip"; @import "common/topic-entrance"; diff --git a/app/assets/stylesheets/common/admin/admin_base.scss b/app/assets/stylesheets/common/admin/admin_base.scss index 8ad76b89218..4b61694769c 100644 --- a/app/assets/stylesheets/common/admin/admin_base.scss +++ b/app/assets/stylesheets/common/admin/admin_base.scss @@ -212,10 +212,10 @@ $mobile-breakpoint: 700px; .admin-container { margin-top: 20px; - .select-box-kit { + .select-kit { width: 350px; } - .select-box-kit.multi-combo-box { + .select-kit.multi-select { width: 500px; } .select-box-kit.dropdown-select-box { @@ -452,7 +452,7 @@ $mobile-breakpoint: 700px; width: 100%; padding-right: 0; } - .select-box-kit { + .select-kit { width: 100% !important; // Needs !important to override hard-coded value @media (max-width: $mobile-breakpoint) { width: 100% !important; // !important overrides hard-coded mobile width of 68px @@ -623,7 +623,7 @@ section.details { margin-left: 0; } - .select-box-kit { + .select-kit { width: inherit; } } diff --git a/app/assets/stylesheets/common/admin/flagging.scss b/app/assets/stylesheets/common/admin/flagging.scss index 0bcdd190b26..debcb8f7864 100644 --- a/app/assets/stylesheets/common/admin/flagging.scss +++ b/app/assets/stylesheets/common/admin/flagging.scss @@ -154,9 +154,9 @@ align-items: center; justify-content: flex-start; - button, .select-box-kit { - margin-bottom: 0.5em; + button { margin-right: 0.5em; + margin-bottom: 0.5em; } } } diff --git a/app/assets/stylesheets/common/base/_topic-list.scss b/app/assets/stylesheets/common/base/_topic-list.scss index bc0164c31bf..9393c7fc822 100644 --- a/app/assets/stylesheets/common/base/_topic-list.scss +++ b/app/assets/stylesheets/common/base/_topic-list.scss @@ -8,7 +8,7 @@ } .list-controls { - .select-box-kit { + .select-kit { align-self: center; &.categories-admin-dropdown, &.category-notifications-button, &.tag-notifications-button { diff --git a/app/assets/stylesheets/common/base/edit-topic-status-update-modal.scss b/app/assets/stylesheets/common/base/edit-topic-status-update-modal.scss index f535f9a3f77..b16a1f70659 100644 --- a/app/assets/stylesheets/common/base/edit-topic-status-update-modal.scss +++ b/app/assets/stylesheets/common/base/edit-topic-status-update-modal.scss @@ -3,7 +3,7 @@ max-height: none; } - .select-box-kit { + .select-kit { width: 50%; } diff --git a/app/assets/stylesheets/common/base/modal.scss b/app/assets/stylesheets/common/base/modal.scss index 1183ad70f79..aa00dc21c71 100644 --- a/app/assets/stylesheets/common/base/modal.scss +++ b/app/assets/stylesheets/common/base/modal.scss @@ -75,7 +75,7 @@ background-color: $secondary; background-clip: padding-box; - .select-box-kit { + .select-kit { width: 220px; } } diff --git a/app/assets/stylesheets/common/base/notifications-button.scss b/app/assets/stylesheets/common/base/notifications-button.scss deleted file mode 100644 index 12e8252a821..00000000000 --- a/app/assets/stylesheets/common/base/notifications-button.scss +++ /dev/null @@ -1,9 +0,0 @@ -.notifications-button, .dropdown-select-box .select-box-kit-row .icons { - .d-icon.regular, .d-icon.muted, .d-icon.watching-first-post { - color: dark-light-choose($primary-medium, $secondary-medium); - } - .d-icon.tracking, .d-icon.watching { - color: $tertiary; - font-weight: normal; - } -} diff --git a/app/assets/stylesheets/common/select-box-kit/categories-admin-dropdown.scss b/app/assets/stylesheets/common/select-box-kit/categories-admin-dropdown.scss deleted file mode 100644 index 9a7a2e522e9..00000000000 --- a/app/assets/stylesheets/common/select-box-kit/categories-admin-dropdown.scss +++ /dev/null @@ -1,12 +0,0 @@ -.select-box-kit { - &.categories-admin-dropdown { - .select-box-kit-select-box-kit-body { - min-width: auto; - width: 250px; - } - - .select-box-kit-header .d-icon { - justify-content: space-between; - } - } -} diff --git a/app/assets/stylesheets/common/select-box-kit/admin-agree-flag-dropdown.scss b/app/assets/stylesheets/common/select-kit/admin-agree-flag-dropdown.scss similarity index 64% rename from app/assets/stylesheets/common/select-box-kit/admin-agree-flag-dropdown.scss rename to app/assets/stylesheets/common/select-kit/admin-agree-flag-dropdown.scss index 46463584cc0..9c1e778499b 100644 --- a/app/assets/stylesheets/common/select-box-kit/admin-agree-flag-dropdown.scss +++ b/app/assets/stylesheets/common/select-kit/admin-agree-flag-dropdown.scss @@ -1,4 +1,4 @@ -.select-box-kit { +.select-box-kit-body, .select-kit { &.dropdown-select-box { &.admin-agree-flag-dropdown { @@ -7,7 +7,9 @@ max-width: 485px; } .select-box-kit-row[data-value="delete-spammer"] .texts .name, - .select-box-kit-row[data-value="delete-spammer"] .icons .d-icon { + .select-kit-row[data-value="delete-spammer"] .texts .name, + .select-box-kit-row[data-value="delete-spammer"] .icons .d-icon, + .select-kit-row[data-value="delete-spammer"] .icons .d-icon { color: $danger; } } diff --git a/app/assets/stylesheets/common/select-box-kit/admin-delete-flag-dropdown.scss b/app/assets/stylesheets/common/select-kit/admin-delete-flag-dropdown.scss similarity index 100% rename from app/assets/stylesheets/common/select-box-kit/admin-delete-flag-dropdown.scss rename to app/assets/stylesheets/common/select-kit/admin-delete-flag-dropdown.scss diff --git a/app/assets/stylesheets/common/select-kit/categories-admin-dropdown.scss b/app/assets/stylesheets/common/select-kit/categories-admin-dropdown.scss new file mode 100644 index 00000000000..9e3326dd0eb --- /dev/null +++ b/app/assets/stylesheets/common/select-kit/categories-admin-dropdown.scss @@ -0,0 +1,12 @@ +.select-box-kit, .select-kit { + &.categories-admin-dropdown { + .select-box-kit-body, .select-kit-body { + min-width: auto; + width: 250px; + } + + .select-box-kit-header .d-icon, .select-kit-header .d-icon { + justify-content: space-between; + } + } +} diff --git a/app/assets/stylesheets/common/select-box-kit/category-chooser.scss b/app/assets/stylesheets/common/select-kit/category-chooser.scss similarity index 92% rename from app/assets/stylesheets/common/select-box-kit/category-chooser.scss rename to app/assets/stylesheets/common/select-kit/category-chooser.scss index e5f30989c07..ed4417f96ae 100644 --- a/app/assets/stylesheets/common/select-box-kit/category-chooser.scss +++ b/app/assets/stylesheets/common/select-kit/category-chooser.scss @@ -1,8 +1,8 @@ -.select-box-kit { +.select-box-kit, .select-kit { &.combo-box { &.category-chooser { width: 300px; - .select-box-kit-row { + .select-box-kit-row, .select-kit-row { display: -webkit-box; display: -ms-flexbox; display: flex; diff --git a/app/assets/stylesheets/common/select-box-kit/combo-box.scss b/app/assets/stylesheets/common/select-kit/combo-box.scss similarity index 80% rename from app/assets/stylesheets/common/select-box-kit/combo-box.scss rename to app/assets/stylesheets/common/select-kit/combo-box.scss index 2c93026e4bc..439279c7b78 100644 --- a/app/assets/stylesheets/common/select-box-kit/combo-box.scss +++ b/app/assets/stylesheets/common/select-kit/combo-box.scss @@ -1,29 +1,29 @@ -.select-box-kit { +.select-box-kit, .select-kit { &.combo-box { border-radius: 3px; - .select-box-kit-body { + .select-box-kit-body, .select-kit-body { width: 100%; } - .select-box-kit-row { + .select-box-kit-row, .select-kit-row { margin: 5px; min-height: 1px; padding: 5px; } - .select-box-kit-filter { + .select-box-kit-filter, .select-kit-filter { line-height: 18px; padding: 5px 10px; border-top: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); border-bottom: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); - .select-box-kit-filter-input { + .filter-input { margin-right: 5px; } } - .select-box-kit-header { + .select-box-kit-header, .select-kit-header { background: $secondary; border: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); border-radius: 3px; @@ -41,14 +41,14 @@ } &.is-disabled { - .select-box-kit-header { + .select-kit-header { background: #e9e9e9; border-color: #ddd; } } &.is-highlighted { - .select-box-kit-header { + .select-kit-header { border: 1px solid $tertiary; -webkit-box-shadow: $tertiary 0px 0px 6px 0px; box-shadow: $tertiary 0px 0px 6px 0px; @@ -56,7 +56,7 @@ } &.is-expanded { - .select-box-kit-wrapper { + .select-kit-wrapper { display: block; border: 1px solid $tertiary; border-radius: 3px; @@ -64,20 +64,20 @@ box-shadow: $tertiary 0px 0px 6px 0px; } - .select-box-kit-header { + .select-kit-header { border-radius: 3px 3px 0 0; border-color: transparent; -webkit-box-shadow: none; box-shadow: none; } - .select-box-kit-body { + .select-kit-body { border-radius: 3px 3px 0 0; } } &.is-expanded.is-above { - .select-box-kit-header { + .select-kit-header { border-radius: 0 0 3px 3px; } } diff --git a/app/assets/stylesheets/common/select-box-kit/dropdown-select-box.scss b/app/assets/stylesheets/common/select-kit/dropdown-select-box.scss similarity index 67% rename from app/assets/stylesheets/common/select-box-kit/dropdown-select-box.scss rename to app/assets/stylesheets/common/select-kit/dropdown-select-box.scss index 670a31e657c..97c0aae8c18 100644 --- a/app/assets/stylesheets/common/select-box-kit/dropdown-select-box.scss +++ b/app/assets/stylesheets/common/select-kit/dropdown-select-box.scss @@ -1,18 +1,35 @@ -.select-box-kit { +.select-box-kit, .select-kit { &.dropdown-select-box { display: -webkit-inline-box; display: -ms-inline-flexbox; display: inline-flex; min-width: auto; + border: none; + + + .d-icon { + color: dark-light-choose(scale-color($primary, $lightness: 40%), scale-color($secondary, $lightness: 60%)); + } + + .d-regular, .d-muted, .d-watching-first-post { + color: dark-light-choose($primary-medium, $secondary-medium); + } + + .d-tracking, .d-watching { + color: $tertiary; + font-weight: normal; + } &.is-expanded { .select-box-kit-collection, - .select-box-kit-body { + .select-box-kit-body, + .select-kit-collection, + .select-kit-body { border-radius: 0; } } - .select-box-kit-body { + .select-box-kit-body, .select-kit-body { border: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); background-clip: padding-box; -webkit-box-shadow: 0 1px 5px rgba(0,0,0,0.4); @@ -21,7 +38,7 @@ width: 300px; } - .select-box-kit-row { + .select-box-kit-row, .select-kit-row { margin: 0; padding: 10px 5px; @@ -47,7 +64,6 @@ align-self: center; margin-right: 0; opacity: 1; - color: dark-light-choose(scale-color($primary, $lightness: 40%), scale-color($secondary, $lightness: 60%)); } } @@ -91,7 +107,7 @@ } } - .select-box-kit-collection { + .select-box-kit-collection, .select-kit-collection { padding: 0; } @@ -99,46 +115,30 @@ -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; - padding: 0; border: 0; - outline: 0; - -webkit-box-pack: start; - -ms-flex-pack: start; - justify-content: flex-start; - background: none; height: 30px; - &.is-focused { - .btn { - border: 1px solid $tertiary; - -webkit-box-shadow: $tertiary 0px 0px 6px 0px; - box-shadow: $tertiary 0px 0px 6px 0px; - } - } + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: justify; + -ms-flex-pack: justify; + justify-content: space-between; + -webkit-box-orient: horizontal; + -webkit-box-direction: normal; + -ms-flex-direction: row; + flex-direction: row; + display: -webkit-inline-box; + display: -ms-inline-flexbox; + display: inline-flex; .d-icon + .d-icon { margin-left: 5px; - font-size: 1.143em; - line-height: 18px; } - .btn { - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; - -webkit-box-pack: justify; - -ms-flex-pack: justify; - justify-content: space-between; - -webkit-box-orient: horizontal; - -webkit-box-direction: normal; - -ms-flex-direction: row; - flex-direction: row; - display: -webkit-inline-box; - display: -ms-inline-flexbox; - display: inline-flex; - height: 100%; - margin: 0; - border: 1px solid transparent + &.is-focused { + outline-style: auto; + outline-color: $tertiary; } } } diff --git a/app/assets/stylesheets/common/select-box-kit/future-date-input-selector.scss b/app/assets/stylesheets/common/select-kit/future-date-input-selector.scss similarity index 93% rename from app/assets/stylesheets/common/select-box-kit/future-date-input-selector.scss rename to app/assets/stylesheets/common/select-kit/future-date-input-selector.scss index 60683bddc42..05771bb9d37 100644 --- a/app/assets/stylesheets/common/select-box-kit/future-date-input-selector.scss +++ b/app/assets/stylesheets/common/select-kit/future-date-input-selector.scss @@ -1,4 +1,4 @@ -.select-box-kit { +.select-box-kit, .select-kit { &.combobox { &.future-date-input-selector { min-width: 50%; diff --git a/app/assets/stylesheets/common/select-box-kit/legacy-combo-box.scss b/app/assets/stylesheets/common/select-kit/legacy-combo-box.scss similarity index 100% rename from app/assets/stylesheets/common/select-box-kit/legacy-combo-box.scss rename to app/assets/stylesheets/common/select-kit/legacy-combo-box.scss diff --git a/app/assets/stylesheets/common/select-box-kit/list-setting.scss b/app/assets/stylesheets/common/select-kit/list-setting.scss similarity index 56% rename from app/assets/stylesheets/common/select-box-kit/list-setting.scss rename to app/assets/stylesheets/common/select-kit/list-setting.scss index eea89e6cb5a..1f7103ef982 100644 --- a/app/assets/stylesheets/common/select-box-kit/list-setting.scss +++ b/app/assets/stylesheets/common/select-kit/list-setting.scss @@ -1,7 +1,7 @@ -.select-box-kit { - &.multi-combo-box { +.select-box-kit, .select-kit { + &.multi-select { &.list-setting { - .select-box-kit-row.create { + .select-box-kit-row.create, .select-kit-row.create { .square { width: 12px; height: 12px; diff --git a/app/assets/stylesheets/common/select-box-kit/multi-combo-box.scss b/app/assets/stylesheets/common/select-kit/multi-select.scss similarity index 61% rename from app/assets/stylesheets/common/select-box-kit/multi-combo-box.scss rename to app/assets/stylesheets/common/select-kit/multi-select.scss index 501afde4e6e..a705282643d 100644 --- a/app/assets/stylesheets/common/select-box-kit/multi-combo-box.scss +++ b/app/assets/stylesheets/common/select-kit/multi-select.scss @@ -1,29 +1,27 @@ -.select-box-kit { - &.multi-combo-box { +.select-box-kit, .select-kit { + &.multi-select { width: 300px; background: $secondary; border: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); border-radius: 0; - .select-box-kit-body { + .select-box-kit-body, .select-kit-body { width: 100%; } - .select-box-kit-row { + .select-box-kit-row, .select-kit-row { margin: 5px; min-height: 1px; padding: 5px; border-radius: 0; } - .select-box-kit-filter { + .select-box-kit-filter, .select-kit-filter { border: 0; } - .multi-combo-box-header { + .multi-select-header { background: $secondary; - border: 0; - border-bottom: 1px solid transparent; &.is-focused { box-shadow: $tertiary 0px 0px 6px 0px; @@ -32,14 +30,14 @@ } &.is-disabled { - .multi-combo-box-header { + .multi-select-header { background: #e9e9e9; border-color: #ddd; } } &.is-highlighted { - .multi-combo-box-header { + .multi-select-header { border-radius: 0; border-bottom: 1px solid transparent; box-shadow: $tertiary 0px 0px 6px 0px; @@ -47,20 +45,19 @@ } &.is-expanded { - .select-box-kit-wrapper { + .select-box-kit-wrapper, .select-kit-wrapper { display: block; border: 1px solid $tertiary; box-shadow: $tertiary 0px 0px 6px 0px; border-radius: 0; } - .multi-combo-box-header { - border-bottom: 1px solid $primary-low; + .multi-select-header { border-radius: 0; box-shadow: none; } - .select-box-kit-body { + .select-box-kit-body, .select-kit-body { border-radius: 0; } } @@ -69,16 +66,20 @@ list-style: none; margin: 0; padding: 5px; - flex: 1; - min-height: 36px; box-sizing: border-box; + display: inline; + list-style-type: none; - li { + .choice { display: inline-flex; box-sizing: border-box; padding: 0 5px; - margin-bottom: 4px; + margin: 2px 0; border: 1px solid transparent; + align-items: center; + justify-content: space-between; + overflow: hidden; + align-items: center; } .filter { @@ -87,8 +88,9 @@ white-space: nowrap; min-width: 50px; padding: 0; + outline: none; - .select-box-kit-filter-input, .select-box-kit-filter-input:focus { + .filter-input, .filter-input:focus { border: none; background: none; display: inline-block; @@ -102,6 +104,21 @@ -webkit-box-shadow: none; box-shadow: none; border-radius: 0; + height: 21px; + } + } + + .selected-color { + .selected-color-wrapper { + display: flex; + flex: 1; + flex-direction: column; + } + + .color-preview { + height: 5px; + margin: 0 2px 2px 2px; + border-radius: 5px; } } @@ -119,26 +136,33 @@ background-color: $primary-low; cursor: pointer; outline: none; - padding: 0; + padding-left: 0; + padding-right: 0; line-height: normal; .name { padding: 0 5px; - line-height: 22px + line-height: 18px; } &.is-highlighted { - border-color: $danger; + box-shadow: 0 0 2px $danger, 0 1px 0 rgba(0,0,0,0.05); } - .d-icon { - margin-right: 5px; - color: $primary-medium; - cursor: pointer; - font-size: 12px; + .locked-icon, .delete-icon { + justify-content: center; + align-items: center; + width: 21px; + height: 21px; + display: inline-flex; + .d-icon { + color: $primary-medium; + cursor: pointer; + font-size: 14px; - &:hover { - color: $primary; + &:hover { + color: $primary; + } } } } diff --git a/app/assets/stylesheets/common/select-box-kit/notifications-button.scss b/app/assets/stylesheets/common/select-kit/notifications-button.scss similarity index 69% rename from app/assets/stylesheets/common/select-box-kit/notifications-button.scss rename to app/assets/stylesheets/common/select-kit/notifications-button.scss index 877cf815ab8..78db012b79f 100644 --- a/app/assets/stylesheets/common/select-box-kit/notifications-button.scss +++ b/app/assets/stylesheets/common/select-kit/notifications-button.scss @@ -1,12 +1,12 @@ -.select-box-kit { +.select-kit { &.dropdown-select-box { &.notifications-button { - .select-box-kit-body { + .select-box-kit-body, .select-kit-body { min-width: 550px; max-width: 550px; } - .select-box-kit-row { + .select-box-kit-row, .select-kit-row { .icons { -ms-flex-item-align: start; align-self: flex-start; diff --git a/app/assets/stylesheets/common/select-box-kit/pinned-button.scss b/app/assets/stylesheets/common/select-kit/pinned-button.scss similarity index 94% rename from app/assets/stylesheets/common/select-box-kit/pinned-button.scss rename to app/assets/stylesheets/common/select-kit/pinned-button.scss index a75a596c6a3..c96365a0e6d 100644 --- a/app/assets/stylesheets/common/select-box-kit/pinned-button.scss +++ b/app/assets/stylesheets/common/select-kit/pinned-button.scss @@ -38,7 +38,7 @@ } .pinned-options { - .select-box-kit-body { + .select-box-kit-body, .select-kit-body { min-width: unset; max-width: unset; width: 550px; diff --git a/app/assets/stylesheets/common/select-box-kit/select-box-kit.scss b/app/assets/stylesheets/common/select-kit/select-kit.scss similarity index 86% rename from app/assets/stylesheets/common/select-box-kit/select-box-kit.scss rename to app/assets/stylesheets/common/select-kit/select-kit.scss index fc8fb103f77..b663b17329d 100644 --- a/app/assets/stylesheets/common/select-box-kit/select-box-kit.scss +++ b/app/assets/stylesheets/common/select-kit/select-kit.scss @@ -1,8 +1,8 @@ -.mobile-view .select-box-kit.is-expanded { +.mobile-view .select-kit.is-expanded { z-index: 1000; } -.select-box-kit { +.select-box-kit, .select-kit { border: 1px solid transparent; min-width: 220px; -webkit-box-sizing: border-box; @@ -31,7 +31,7 @@ &.is-expanded { z-index: 999; - .select-box-kit-body { + .select-kit-body { display: -webkit-box; display: -ms-flexbox; display: flex; @@ -44,18 +44,22 @@ top: 0; } - .select-box-kit-collection, { + .select-kit-collection, { border-radius: inherit; } } &.is-above { - .select-box-kit-body { + .select-kit-body { bottom: 0; top: auto; } - .select-box-kit-wrapper { + .select-kit-filter { + border-top: 0; + } + + .select-kit-wrapper { bottom: 0; top: auto; } @@ -65,7 +69,7 @@ opacity: 0.7; } - .select-box-kit-header { + .select-box-kit-header, .select-kit-header { border: 1px solid transparent; box-sizing: border-box; overflow: hidden; @@ -133,14 +137,14 @@ } } - .select-box-kit-body { + .select-box-kit-body, .select-kit-body { display: none; background: $secondary; -webkit-box-sizing: border-box; box-sizing: border-box; } - .select-box-kit-row { + .select-box-kit-row, .select-kit-row { cursor: pointer; line-height: normal; outline: none; @@ -181,7 +185,7 @@ } } - .select-box-kit-collection { + .select-box-kit-collection, .select-kit-collection { background: $secondary; overflow-x: hidden; overflow-y: auto; @@ -189,11 +193,11 @@ -webkit-overflow-scrolling: touch; margin: 0; - .select-box-kit-collection { + .select-kit-collection { padding: 0; margin: 0; - &:hover .select-box-kit-row.is-highlighted:hover { + &:hover .select-kit-row.is-highlighted:hover { background: $tertiary-low; } } @@ -215,7 +219,7 @@ } } - .select-box-kit-filter { + .select-box-kit-filter, .select-kit-filter { display: -webkit-box; display: -ms-flexbox; display: flex; @@ -226,7 +230,7 @@ -ms-flex-pack: justify; justify-content: space-between; - .select-box-kit-filter-input, .select-box-kit-filter-input:focus, .select-box-kit-filter-input:active { + .filter-input, .filter-input:focus, .filter-input:active { background: none; margin: 0; padding: 0; @@ -255,10 +259,10 @@ } } - .select-box-kit-wrapper { + .select-box-kit-wrapper, .select-kit-wrapper { position: absolute; - top: -1px; - left: -1px; + top: 0; + left: 0; background: none; display: none; -webkit-box-sizing: border-box; @@ -266,17 +270,4 @@ pointer-events: none; border: 1px solid transparent; } - - .select-box-kit-offscreen, .select-box-kit-offscreen:focus { - margin: -1px; - width: 1px; - height: 1px; - border: 0; - padding: 0; - overflow: hidden; - position: fixed; - outline: 0; - left: 0px; - top: 0px; - } } diff --git a/app/assets/stylesheets/common/select-box-kit/topic-notifications-button.scss b/app/assets/stylesheets/common/select-kit/topic-notifications-button.scss similarity index 100% rename from app/assets/stylesheets/common/select-box-kit/topic-notifications-button.scss rename to app/assets/stylesheets/common/select-kit/topic-notifications-button.scss diff --git a/app/assets/stylesheets/mobile/topic-list.scss b/app/assets/stylesheets/mobile/topic-list.scss index 806ab8cb1a7..49c1dd29c0a 100644 --- a/app/assets/stylesheets/mobile/topic-list.scss +++ b/app/assets/stylesheets/mobile/topic-list.scss @@ -53,7 +53,7 @@ } } - .select-box-kit { + .select-kit { &.categories-admin-dropdown, &.category-notifications-button, &.tag-notifications-button { margin-top: 5px; } diff --git a/app/assets/stylesheets/wizard.scss b/app/assets/stylesheets/wizard.scss index 7d84bb53aef..ab0b6f3601d 100644 --- a/app/assets/stylesheets/wizard.scss +++ b/app/assets/stylesheets/wizard.scss @@ -4,7 +4,7 @@ @import "vendor/sweetalert"; @import "common/foundation/colors"; @import "common/foundation/variables"; -@import "common/select-box-kit/*"; +@import "common/select-kit/*"; body.wizard { background-color: #fff; diff --git a/config/locales/client.ar.yml b/config/locales/client.ar.yml index 38f66f95508..a8246952beb 100644 --- a/config/locales/client.ar.yml +++ b/config/locales/client.ar.yml @@ -1193,7 +1193,7 @@ ar: shift: 'Shift' ctrl: 'Ctrl' alt: 'Alt' - select_box: + select_kit: default_header_text: اختر... no_content: لا يوجد نتائج مطابقة filter_placeholder: بحث... diff --git a/config/locales/client.de.yml b/config/locales/client.de.yml index 2a97f303f9b..29f6944fd05 100644 --- a/config/locales/client.de.yml +++ b/config/locales/client.de.yml @@ -1040,7 +1040,7 @@ de: shift: 'Umschalt' ctrl: 'Strg' alt: 'Alt' - select_box: + select_kit: default_header_text: Auswählen… no_content: Keine Treffer gefunden filter_placeholder: Suchen… diff --git a/config/locales/client.el.yml b/config/locales/client.el.yml index 6ce5ecf9da4..97eb8ef1fac 100644 --- a/config/locales/client.el.yml +++ b/config/locales/client.el.yml @@ -1040,7 +1040,7 @@ el: shift: ' Shift' ctrl: 'Ctrl' alt: 'Alt' - select_box: + select_kit: default_header_text: Επίλεξε... no_content: Δεν βρέθηκαν αποτελέσματα filter_placeholder: Αναζήτηση... diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 4080de01ee5..dfba2c103d3 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -1165,7 +1165,7 @@ en: ctrl: 'Ctrl' alt: 'Alt' - select_box: + select_kit: default_header_text: Select... no_content: No matches found filter_placeholder: Search... diff --git a/config/locales/client.es.yml b/config/locales/client.es.yml index a93159b6048..3f98e7632c3 100644 --- a/config/locales/client.es.yml +++ b/config/locales/client.es.yml @@ -1022,7 +1022,7 @@ es: shift: 'Shift' ctrl: 'Ctrl' alt: 'Alt' - select_box: + select_kit: default_header_text: Seleccionar... no_content: Ningún resultado filter_placeholder: Buscar... diff --git a/config/locales/client.fa_IR.yml b/config/locales/client.fa_IR.yml index d5c32a495d4..64b3713e55a 100644 --- a/config/locales/client.fa_IR.yml +++ b/config/locales/client.fa_IR.yml @@ -981,7 +981,7 @@ fa_IR: shift: 'Shift' ctrl: 'Ctrl' alt: 'Alt' - select_box: + select_kit: default_header_text: انتخاب... no_content: چیزی یافت نشد. filter_placeholder: جستجو... diff --git a/config/locales/client.fi.yml b/config/locales/client.fi.yml index 8749733268a..1fa33f89a8b 100644 --- a/config/locales/client.fi.yml +++ b/config/locales/client.fi.yml @@ -1036,7 +1036,7 @@ fi: shift: 'Shift' ctrl: 'Ctrl' alt: 'Alt' - select_box: + select_kit: default_header_text: Valitse... no_content: Ei osumia filter_placeholder: Hae... diff --git a/config/locales/client.fr.yml b/config/locales/client.fr.yml index dc5879e7e9c..91b5787792b 100644 --- a/config/locales/client.fr.yml +++ b/config/locales/client.fr.yml @@ -1036,7 +1036,7 @@ fr: shift: 'Maj' ctrl: 'Ctrl' alt: 'Alt' - select_box: + select_kit: default_header_text: Sélectionner… no_content: Aucune correspondance trouvée filter_placeholder: Recherche... diff --git a/config/locales/client.it.yml b/config/locales/client.it.yml index 1dc4f872800..5444f8fa986 100644 --- a/config/locales/client.it.yml +++ b/config/locales/client.it.yml @@ -1040,7 +1040,7 @@ it: shift: 'Maiusc' ctrl: 'Ctrl' alt: 'Alt' - select_box: + select_kit: default_header_text: Selezione... no_content: Nessun risultato trovato filter_placeholder: Ricerca... diff --git a/config/locales/client.ja.yml b/config/locales/client.ja.yml index 20e98796a2b..9375bc1d969 100644 --- a/config/locales/client.ja.yml +++ b/config/locales/client.ja.yml @@ -990,7 +990,7 @@ ja: shift: 'Shift' ctrl: 'Ctrl' alt: 'Alt' - select_box: + select_kit: default_header_text: 選択... no_content: 一致する結果が見つかりませんでした。 filter_placeholder: 検索... diff --git a/config/locales/client.ko.yml b/config/locales/client.ko.yml index 078091609ef..7496a873804 100644 --- a/config/locales/client.ko.yml +++ b/config/locales/client.ko.yml @@ -996,7 +996,7 @@ ko: shift: 'Shift' ctrl: 'Ctrl' alt: 'Alt' - select_box: + select_kit: default_header_text: 선택... no_content: 검색 결과가 없습니다 filter_placeholder: 검색... diff --git a/config/locales/client.nb_NO.yml b/config/locales/client.nb_NO.yml index 831a1665d69..206a30e05d6 100644 --- a/config/locales/client.nb_NO.yml +++ b/config/locales/client.nb_NO.yml @@ -1039,7 +1039,7 @@ nb_NO: shift: 'Shift' ctrl: 'Ctrl' alt: 'Alt' - select_box: + select_kit: default_header_text: Velg… no_content: Ingen treff funnet filter_placeholder: Søk… diff --git a/config/locales/client.nl.yml b/config/locales/client.nl.yml index 07fbf32c80d..8acb11126cb 100644 --- a/config/locales/client.nl.yml +++ b/config/locales/client.nl.yml @@ -1033,7 +1033,7 @@ nl: shift: 'Shift' ctrl: 'Ctrl' alt: 'Alt' - select_box: + select_kit: default_header_text: Selecteer... no_content: Geen resultaten gevonden filter_placeholder: Zoeken... diff --git a/config/locales/client.pl_PL.yml b/config/locales/client.pl_PL.yml index 07c52c7fa07..0442c9cae98 100644 --- a/config/locales/client.pl_PL.yml +++ b/config/locales/client.pl_PL.yml @@ -1111,7 +1111,7 @@ pl_PL: shift: 'Shift' ctrl: 'Ctrl' alt: 'Alt' - select_box: + select_kit: default_header_text: Wybierz... no_content: Nie znaleziono dopasowań filter_placeholder: Wyszukiwanie... diff --git a/config/locales/client.pt.yml b/config/locales/client.pt.yml index 8684f7b1d66..e2ab135823b 100644 --- a/config/locales/client.pt.yml +++ b/config/locales/client.pt.yml @@ -1010,7 +1010,7 @@ pt: shift: 'Shift' ctrl: 'Ctrl' alt: 'Alt' - select_box: + select_kit: filter_placeholder: Pesquisar... emoji_picker: filter_placeholder: Pesquisar por emoji diff --git a/config/locales/client.ru.yml b/config/locales/client.ru.yml index 56e57730c98..1e5ada6e734 100644 --- a/config/locales/client.ru.yml +++ b/config/locales/client.ru.yml @@ -1094,7 +1094,7 @@ ru: shift: 'Shift' ctrl: 'Ctrl' alt: 'Alt' - select_box: + select_kit: filter_placeholder: Искать... emoji_picker: filter_placeholder: Искать emoji diff --git a/config/locales/client.vi.yml b/config/locales/client.vi.yml index cca5bc36ead..6c2ac34a53f 100644 --- a/config/locales/client.vi.yml +++ b/config/locales/client.vi.yml @@ -951,7 +951,7 @@ vi: shift: 'Shift' ctrl: 'Ctrl' alt: 'Alt' - select_box: + select_kit: default_header_text: Chọn... no_content: Không tìm thấy filter_placeholder: Tìm kiến... diff --git a/config/locales/client.zh_CN.yml b/config/locales/client.zh_CN.yml index 13dba3dfcc7..5de44be5809 100644 --- a/config/locales/client.zh_CN.yml +++ b/config/locales/client.zh_CN.yml @@ -996,7 +996,7 @@ zh_CN: shift: 'Shift' ctrl: 'Ctrl' alt: 'Alt' - select_box: + select_kit: default_header_text: 选择... no_content: 无符合的结果 filter_placeholder: 搜索…… diff --git a/plugins/discourse-details/test/javascripts/acceptance/details-button-test.js.es6 b/plugins/discourse-details/test/javascripts/acceptance/details-button-test.js.es6 index b0f25283ec5..f4639ca26c8 100644 --- a/plugins/discourse-details/test/javascripts/acceptance/details-button-test.js.es6 +++ b/plugins/discourse-details/test/javascripts/acceptance/details-button-test.js.es6 @@ -11,7 +11,7 @@ test('details button', (assert) => { click('#create-topic'); click('button.options'); - click('.popup-menu .d-icon-caret-right'); + click('.popup-menu .d-caret-right'); andThen(() => { assert.equal( @@ -30,7 +30,7 @@ test('details button', (assert) => { }); click('button.options'); - click('.popup-menu .d-icon-caret-right'); + click('.popup-menu .d-caret-right'); andThen(() => { assert.equal( @@ -53,7 +53,7 @@ test('details button', (assert) => { }); click('button.options'); - click('.popup-menu .d-icon-caret-right'); + click('.popup-menu .d-caret-right'); andThen(() => { assert.equal( @@ -76,7 +76,7 @@ test('details button', (assert) => { }); click('button.options'); - click('.popup-menu .d-icon-caret-right'); + click('.popup-menu .d-caret-right'); andThen(() => { assert.equal( @@ -105,7 +105,7 @@ test('details button surrounds all selected text in a single details block', (as }); click('button.options'); - click('.popup-menu .d-icon-caret-right'); + click('.popup-menu .d-caret-right'); andThen(() => { assert.equal( diff --git a/plugins/poll/test/javascripts/widgets/discourse-poll-option-test.js.es6 b/plugins/poll/test/javascripts/widgets/discourse-poll-option-test.js.es6 index 75035b6651c..32ab64e6a30 100644 --- a/plugins/poll/test/javascripts/widgets/discourse-poll-option-test.js.es6 +++ b/plugins/poll/test/javascripts/widgets/discourse-poll-option-test.js.es6 @@ -14,7 +14,7 @@ widgetTest('single, not selected', { }, test(assert) { - assert.ok(find('li .d-icon-circle-o:eq(0)').length === 1); + assert.ok(find('li .d-circle-o:eq(0)').length === 1); } }); @@ -27,7 +27,7 @@ widgetTest('single, selected', { }, test(assert) { - assert.ok(find('li .d-icon-dot-circle-o:eq(0)').length === 1); + assert.ok(find('li .d-dot-circle-o:eq(0)').length === 1); } }); @@ -43,7 +43,7 @@ widgetTest('multi, not selected', { }, test(assert) { - assert.ok(find('li .d-icon-square-o:eq(0)').length === 1); + assert.ok(find('li .d-square-o:eq(0)').length === 1); } }); @@ -59,6 +59,6 @@ widgetTest('multi, selected', { }, test(assert) { - assert.ok(find('li .d-icon-check-square-o:eq(0)').length === 1); + assert.ok(find('li .d-check-square-o:eq(0)').length === 1); } }); diff --git a/test/javascripts/acceptance/admin-flags-test.js.es6 b/test/javascripts/acceptance/admin-flags-test.js.es6 index 3d448184334..3b25ee2f087 100644 --- a/test/javascripts/acceptance/admin-flags-test.js.es6 +++ b/test/javascripts/acceptance/admin-flags-test.js.es6 @@ -16,11 +16,11 @@ QUnit.test("flagged posts - agree", assert => { visit("/admin/flags/active"); andThen(() => { - expandSelectBoxKit('.agree-flag'); + expandSelectKit('.agree-flag'); }); andThen(() => { - selectBoxKitSelectRow('confirm-agree-keep', { selector: '.agree-flag'}); + selectKitSelectRow('confirm-agree-keep', { selector: '.agree-flag'}); }); andThen(() => { @@ -32,11 +32,11 @@ QUnit.test("flagged posts - agree + hide", assert => { visit("/admin/flags/active"); andThen(() => { - expandSelectBoxKit('.agree-flag'); + expandSelectKit('.agree-flag'); }); andThen(() => { - selectBoxKitSelectRow('confirm-agree-hide', { selector: '.agree-flag'}); + selectKitSelectRow('confirm-agree-hide', { selector: '.agree-flag'}); }); andThen(() => { @@ -48,11 +48,11 @@ QUnit.test("flagged posts - agree + deleteSpammer", assert => { visit("/admin/flags/active"); andThen(() => { - expandSelectBoxKit('.agree-flag'); + expandSelectKit('.agree-flag'); }); andThen(() => { - selectBoxKitSelectRow('delete-spammer', { selector: '.agree-flag'}); + selectKitSelectRow('delete-spammer', { selector: '.agree-flag'}); }); click('.confirm-delete'); @@ -82,11 +82,11 @@ QUnit.test("flagged posts - delete + defer", assert => { visit("/admin/flags/active"); andThen(() => { - expandSelectBoxKit('.delete-flag'); + expandSelectKit('.delete-flag'); }); andThen(() => { - selectBoxKitSelectRow('delete-defer', { selector: '.delete-flag'}); + selectKitSelectRow('delete-defer', { selector: '.delete-flag'}); }); andThen(() => { @@ -98,11 +98,11 @@ QUnit.test("flagged posts - delete + agree", assert => { visit("/admin/flags/active"); andThen(() => { - expandSelectBoxKit('.delete-flag'); + expandSelectKit('.delete-flag'); }); andThen(() => { - selectBoxKitSelectRow('delete-agree', { selector: '.delete-flag'}); + selectKitSelectRow('delete-agree', { selector: '.delete-flag'}); }); andThen(() => { @@ -114,11 +114,11 @@ QUnit.test("flagged posts - delete + deleteSpammer", assert => { visit("/admin/flags/active"); andThen(() => { - expandSelectBoxKit('.delete-flag'); + expandSelectKit('.delete-flag'); }); andThen(() => { - selectBoxKitSelectRow('delete-spammer', { selector: '.delete-flag'}); + selectKitSelectRow('delete-spammer', { selector: '.delete-flag'}); }); click('.confirm-delete'); diff --git a/test/javascripts/acceptance/admin-suspend-user-test.js.es6 b/test/javascripts/acceptance/admin-suspend-user-test.js.es6 index bd1fb803563..cfe73206013 100644 --- a/test/javascripts/acceptance/admin-suspend-user-test.js.es6 +++ b/test/javascripts/acceptance/admin-suspend-user-test.js.es6 @@ -44,8 +44,8 @@ QUnit.test("suspend, then unsuspend a user", assert => { andThen(() => { assert.equal(find('.perform-suspend[disabled]').length, 1, 'disabled by default'); - expandSelectBoxKit('.suspend-until .combobox'); - selectBoxKitSelectRow('tomorrow', { selector: '.suspend-until .combobox'}); + expandSelectKit('.suspend-until .combobox'); + selectKitSelectRow('tomorrow', { selector: '.suspend-until .combobox'}); }); fillIn('.suspend-reason', "for breaking the rules"); diff --git a/test/javascripts/acceptance/category-chooser-test.js.es6 b/test/javascripts/acceptance/category-chooser-test.js.es6 index 9f645bc6b00..793674295f8 100644 --- a/test/javascripts/acceptance/category-chooser-test.js.es6 +++ b/test/javascripts/acceptance/category-chooser-test.js.es6 @@ -11,10 +11,10 @@ QUnit.test("does not display uncategorized if not allowed", assert => { visit("/"); click('#create-topic'); - ('.category-chooser'); + expandSelectKit('.category-chooser'); andThen(() => { - assert.ok(selectBox('.category-chooser').rowByIndex(0).name() !== 'uncategorized'); + assert.ok(selectKit('.category-chooser').rowByIndex(0).name() !== 'uncategorized'); }); }); @@ -22,6 +22,6 @@ QUnit.test("prefill category when category_id is set", assert => { visit("/new-topic?category_id=1"); andThen(() => { - assert.equal(selectBox('.category-chooser').header.name(), 'bug'); + assert.equal(selectKit('.category-chooser').header.name(), 'bug'); }); }); diff --git a/test/javascripts/acceptance/category-edit-test.js.es6 b/test/javascripts/acceptance/category-edit-test.js.es6 index 24d1eceef41..5f0415a43cb 100644 --- a/test/javascripts/acceptance/category-edit-test.js.es6 +++ b/test/javascripts/acceptance/category-edit-test.js.es6 @@ -75,9 +75,9 @@ QUnit.test("Subcategory list settings", assert => { click('.edit-category-general'); - expandSelectBoxKit('.edit-category-tab-general .category-chooser'); + expandSelectKit('.edit-category-tab-general .category-chooser'); - selectBoxKitSelectRow(3, {selector: '.edit-category-tab-general .category-chooser'}); + selectKitSelectRow(3, {selector: '.edit-category-tab-general .category-chooser'}); click('.edit-category-settings'); andThen(() => { diff --git a/test/javascripts/acceptance/composer-test.js.es6 b/test/javascripts/acceptance/composer-test.js.es6 index 48afc43867d..97df4f971ce 100644 --- a/test/javascripts/acceptance/composer-test.js.es6 +++ b/test/javascripts/acceptance/composer-test.js.es6 @@ -264,7 +264,7 @@ QUnit.test("Composer can toggle between reply and createTopic", assert => { click('.topic-post:eq(0) button.reply'); click('button.options'); - click('.popup-menu .d-icon-eye-slash'); + click('.popup-menu .d-eye-slash'); andThen(() => { assert.ok( find('.composer-fields .whisper').text().indexOf(I18n.t("composer.whisper")) > 0, @@ -286,7 +286,7 @@ QUnit.test("Composer can toggle between reply and createTopic", assert => { }); click('button.options'); - click('.popup-menu .d-icon-eye-slash'); + click('.popup-menu .d-eye-slash'); andThen(() => { assert.ok( find('.composer-fields .whisper').text().indexOf(I18n.t("composer.unlist")) > 0, diff --git a/test/javascripts/acceptance/search-full-test.js.es6 b/test/javascripts/acceptance/search-full-test.js.es6 index 24ad402b30b..db5dc8cee85 100644 --- a/test/javascripts/acceptance/search-full-test.js.es6 +++ b/test/javascripts/acceptance/search-full-test.js.es6 @@ -136,10 +136,10 @@ QUnit.test("update category through advanced search ui", assert => { visit("/search"); fillIn('.search input.full-page-search', 'none'); click('.search-advanced-btn'); - fillIn('.search-advanced-options .category-selector', 'faq'); - click('.search-advanced-options .category-selector'); - keyEvent('.search-advanced-options .category-selector', 'keydown', 8); - keyEvent('.search-advanced-options .category-selector', 'keydown', 9); + + expandSelectKit('.search-advanced-options .category-chooser'); + selectKitFillInFilter('faq', { selector: '.search-advanced-options .category-chooser' }); + selectKitSelectRow(4, { selector: '.search-advanced-options .category-chooser' }); andThen(() => { assert.ok(exists('.search-advanced-options .badge-category:contains("faq")'), 'has "faq" populated'); @@ -257,12 +257,12 @@ QUnit.test("update in filter through advanced search ui", assert => { fillIn('.search input.full-page-search', 'none'); click('.search-advanced-btn'); - expandSelectBoxKit('.search-advanced-options .select-box-kit#in'); - selectBoxKitSelectRow('bookmarks', { selector: '.search-advanced-options .select-box-kit#in' }); - fillIn('.search-advanced-options .select-box-kit#in', 'bookmarks'); + expandSelectKit('.search-advanced-options .select-kit#in'); + selectKitSelectRow('bookmarks', { selector: '.search-advanced-options .select-kit#in' }); + fillIn('.search-advanced-options .select-kit#in', 'bookmarks'); andThen(() => { - assert.ok(exists(selectBox('.search-advanced-options .select-box-kit#in').rowByName("I\'ve bookmarked").el), 'has "I\'ve bookmarked" populated'); + assert.ok(exists(selectKit('.search-advanced-options .select-kit#in').rowByName("I\'ve bookmarked").el), 'has "I\'ve bookmarked" populated'); assert.equal(find('.search input.full-page-search').val(), "none in:bookmarks", 'has updated search term to "none in:bookmarks"'); }); }); @@ -271,12 +271,12 @@ QUnit.test("update status through advanced search ui", assert => { visit("/search"); fillIn('.search input.full-page-search', 'none'); click('.search-advanced-btn'); - expandSelectBoxKit('.search-advanced-options .select-box-kit#status'); - selectBoxKitSelectRow('closed', { selector: '.search-advanced-options .select-box-kit#status' }); - fillIn('.search-advanced-options .select-box-kit#status', 'closed'); + expandSelectKit('.search-advanced-options .select-kit#status'); + selectKitSelectRow('closed', { selector: '.search-advanced-options .select-kit#status' }); + fillIn('.search-advanced-options .select-kit#status', 'closed'); andThen(() => { - assert.ok(exists(selectBox('.search-advanced-options .select-box-kit#status').rowByName("are closed").el), 'has "are closed" populated'); + assert.ok(exists(selectKit('.search-advanced-options .select-kit#status').rowByName("are closed").el), 'has "are closed" populated'); assert.equal(find('.search input.full-page-search').val(), "none status:closed", 'has updated search term to "none status:closed"'); }); }); @@ -286,12 +286,12 @@ QUnit.test("update post time through advanced search ui", assert => { fillIn('.search input.full-page-search', 'none'); click('.search-advanced-btn'); fillIn('#search-post-date', '2016-10-05'); - expandSelectBoxKit('.search-advanced-options .select-box-kit#postTime'); - selectBoxKitSelectRow('after', { selector: '.search-advanced-options .select-box-kit#postTime' }); - fillIn('.search-advanced-options .select-box-kit#postTime', 'after'); + expandSelectKit('.search-advanced-options .select-kit#postTime'); + selectKitSelectRow('after', { selector: '.search-advanced-options .select-kit#postTime' }); + fillIn('.search-advanced-options .select-kit#postTime', 'after'); andThen(() => { - assert.ok(exists(selectBox('.search-advanced-options .select-box-kit#postTime').rowByName("after").el), 'has "after" populated'); + assert.ok(exists(selectKit('.search-advanced-options .select-kit#postTime').rowByName("after").el), 'has "after" populated'); assert.equal(find('.search-advanced-options #search-post-date').val(), "2016-10-05", 'has "2016-10-05" populated'); assert.equal(find('.search input.full-page-search').val(), "none after:2016-10-05", 'has updated search term to "none after:2016-10-05"'); }); diff --git a/test/javascripts/acceptance/search-test.js.es6 b/test/javascripts/acceptance/search-test.js.es6 index a5ce94669b3..d9fb690638e 100644 --- a/test/javascripts/acceptance/search-test.js.es6 +++ b/test/javascripts/acceptance/search-test.js.es6 @@ -89,20 +89,20 @@ QUnit.test("Search with context", assert => { QUnit.test("Right filters are shown to anonymous users", assert => { visit("/search?expanded=true"); - expandSelectBoxKit(".select-box-kit#in"); + expandSelectKit(".select-kit#in"); andThen(() => { - assert.ok(exists('.select-box-kit#in .select-box-kit-row[data-value=first]')); - assert.ok(exists('.select-box-kit#in .select-box-kit-row[data-value=pinned]')); - assert.ok(exists('.select-box-kit#in .select-box-kit-row[data-value=unpinned]')); - assert.ok(exists('.select-box-kit#in .select-box-kit-row[data-value=wiki]')); - assert.ok(exists('.select-box-kit#in .select-box-kit-row[data-value=images]')); + assert.ok(exists('.select-kit#in .select-kit-row[data-value=first]')); + assert.ok(exists('.select-kit#in .select-kit-row[data-value=pinned]')); + assert.ok(exists('.select-kit#in .select-kit-row[data-value=unpinned]')); + assert.ok(exists('.select-kit#in .select-kit-row[data-value=wiki]')); + assert.ok(exists('.select-kit#in .select-kit-row[data-value=images]')); - assert.notOk(exists('.select-box-kit#in .select-box-kit-row[data-value=unseen]')); - assert.notOk(exists('.select-box-kit#in .select-box-kit-row[data-value=posted]')); - assert.notOk(exists('.select-box-kit#in .select-box-kit-row[data-value=watching]')); - assert.notOk(exists('.select-box-kit#in .select-box-kit-row[data-value=tracking]')); - assert.notOk(exists('.select-box-kit#in .select-box-kit-row[data-value=bookmarks]')); + assert.notOk(exists('.select-kit#in .select-kit-row[data-value=unseen]')); + assert.notOk(exists('.select-kit#in .select-kit-row[data-value=posted]')); + assert.notOk(exists('.select-kit#in .select-kit-row[data-value=watching]')); + assert.notOk(exists('.select-kit#in .select-kit-row[data-value=tracking]')); + assert.notOk(exists('.select-kit#in .select-kit-row[data-value=bookmarks]')); assert.notOk(exists('.search-advanced-options .in-likes')); assert.notOk(exists('.search-advanced-options .in-private')); @@ -115,20 +115,20 @@ QUnit.test("Right filters are shown to logged-in users", assert => { Discourse.reset(); visit("/search?expanded=true"); - expandSelectBoxKit(".select-box-kit#in"); + expandSelectKit(".select-kit#in"); andThen(() => { - assert.ok(exists('.select-box-kit#in .select-box-kit-row[data-value=first]')); - assert.ok(exists('.select-box-kit#in .select-box-kit-row[data-value=pinned]')); - assert.ok(exists('.select-box-kit#in .select-box-kit-row[data-value=unpinned]')); - assert.ok(exists('.select-box-kit#in .select-box-kit-row[data-value=wiki]')); - assert.ok(exists('.select-box-kit#in .select-box-kit-row[data-value=images]')); + assert.ok(exists('.select-kit#in .select-kit-row[data-value=first]')); + assert.ok(exists('.select-kit#in .select-kit-row[data-value=pinned]')); + assert.ok(exists('.select-kit#in .select-kit-row[data-value=unpinned]')); + assert.ok(exists('.select-kit#in .select-kit-row[data-value=wiki]')); + assert.ok(exists('.select-kit#in .select-kit-row[data-value=images]')); - assert.ok(exists('.select-box-kit#in .select-box-kit-row[data-value=unseen]')); - assert.ok(exists('.select-box-kit#in .select-box-kit-row[data-value=posted]')); - assert.ok(exists('.select-box-kit#in .select-box-kit-row[data-value=watching]')); - assert.ok(exists('.select-box-kit#in .select-box-kit-row[data-value=tracking]')); - assert.ok(exists('.select-box-kit#in .select-box-kit-row[data-value=bookmarks]')); + assert.ok(exists('.select-kit#in .select-kit-row[data-value=unseen]')); + assert.ok(exists('.select-kit#in .select-kit-row[data-value=posted]')); + assert.ok(exists('.select-kit#in .select-kit-row[data-value=watching]')); + assert.ok(exists('.select-kit#in .select-kit-row[data-value=tracking]')); + assert.ok(exists('.select-kit#in .select-kit-row[data-value=bookmarks]')); assert.ok(exists('.search-advanced-options .in-likes')); assert.ok(exists('.search-advanced-options .in-private')); diff --git a/test/javascripts/acceptance/topic-notifications-button-test.js.es6 b/test/javascripts/acceptance/topic-notifications-button-test.js.es6 index fa21ef4e96a..7a0934ffc57 100644 --- a/test/javascripts/acceptance/topic-notifications-button-test.js.es6 +++ b/test/javascripts/acceptance/topic-notifications-button-test.js.es6 @@ -28,12 +28,12 @@ QUnit.test("Updating topic notification level", assert => { ); }); - expandSelectBoxKit(notificationOptions); - selectBoxKitSelectRow("3", { selector: notificationOptions}); + expandSelectKit(notificationOptions); + selectKitSelectRow("3", { selector: notificationOptions}); andThen(() => { assert.equal( - selectBox(notificationOptions).selectedRow.name(), + selectKit(notificationOptions).selectedRow.name(), "watching", "it should display the right notification level" ); diff --git a/test/javascripts/acceptance/topic-test.js.es6 b/test/javascripts/acceptance/topic-test.js.es6 index 72f8518070c..6ffaa1a6f09 100644 --- a/test/javascripts/acceptance/topic-test.js.es6 +++ b/test/javascripts/acceptance/topic-test.js.es6 @@ -33,7 +33,7 @@ QUnit.test("Share Popup", assert => { QUnit.test("Showing and hiding the edit controls", assert => { visit("/t/internationalization-localization/280"); - click('#topic-title .d-icon-pencil'); + click('#topic-title .d-pencil'); andThen(() => { assert.ok(exists('#edit-title'), 'it shows the editing controls'); @@ -49,13 +49,13 @@ QUnit.test("Showing and hiding the edit controls", assert => { QUnit.test("Updating the topic title and category", assert => { visit("/t/internationalization-localization/280"); - click('#topic-title .d-icon-pencil'); + click('#topic-title .d-pencil'); fillIn('#edit-title', 'this is the new title'); - expandSelectBoxKit('.title-wrapper .category-chooser'); + expandSelectKit('.title-wrapper .category-chooser'); - selectBoxKitSelectRow(4, {selector: '.title-wrapper .category-chooser'}); + selectKitSelectRow(4, {selector: '.title-wrapper .category-chooser'}); click('#topic-title .submit-edit'); @@ -103,7 +103,7 @@ QUnit.test("Reply as new topic", assert => { "it fills composer with the ring string" ); assert.equal( - selectBox('.category-chooser').header.name(), "feature", + selectKit('.category-chooser').header.name(), "feature", "it fills category selector with the right category" ); }); @@ -164,7 +164,7 @@ QUnit.test("Visit topic routes", assert => { QUnit.test("Updating the topic title with emojis", assert => { visit("/t/internationalization-localization/280"); - click('#topic-title .d-icon-pencil'); + click('#topic-title .d-pencil'); fillIn('#edit-title', 'emojis title :bike: :blonde_woman:t6:'); diff --git a/test/javascripts/components/categories-admin-dropdown-test.js.es6 b/test/javascripts/components/categories-admin-dropdown-test.js.es6 index 07593db3e62..3c999f03e9d 100644 --- a/test/javascripts/components/categories-admin-dropdown-test.js.es6 +++ b/test/javascripts/components/categories-admin-dropdown-test.js.es6 @@ -5,15 +5,15 @@ componentTest('default', { template: '{{categories-admin-dropdown}}', test(assert) { - const $selectBox = selectBox('.categories-admin-dropdown'); + const $selectKit = selectKit('.categories-admin-dropdown'); - assert.equal($selectBox.el.find(".d-icon-bars").length, 1); - assert.equal($selectBox.el.find(".d-icon-caret-down").length, 1); + assert.equal($selectKit.el.find(".d-bars").length, 1); + assert.equal($selectKit.el.find(".d-caret-down").length, 1); - expandSelectBoxKit(); + expandSelectKit(); andThen(() => { - assert.equal($selectBox.rowByValue("create").name(), "New Category"); + assert.equal($selectKit.rowByValue("create").name(), "New Category"); }); } }); diff --git a/test/javascripts/components/category-chooser-test.js.es6 b/test/javascripts/components/category-chooser-test.js.es6 index d6fca21fd09..ec29639148e 100644 --- a/test/javascripts/components/category-chooser-test.js.es6 +++ b/test/javascripts/components/category-chooser-test.js.es6 @@ -6,10 +6,10 @@ componentTest('with value', { template: '{{category-chooser value=2}}', test(assert) { - expandSelectBoxKit(); + expandSelectKit(); andThen(() => { - assert.equal(selectBox('.category-chooser').header.name(), "feature"); + assert.equal(selectKit('.category-chooser').header.name(), "feature"); }); } }); @@ -18,10 +18,10 @@ componentTest('with excludeCategoryId', { template: '{{category-chooser excludeCategoryId=2}}', test(assert) { - expandSelectBoxKit(); + expandSelectKit(); andThen(() => { - assert.equal(selectBox('.category-chooser').rowByValue(2).el.length, 0); + assert.equal(selectKit('.category-chooser').rowByValue(2).el.length, 0); }); } }); @@ -30,12 +30,12 @@ componentTest('with scopedCategoryId', { template: '{{category-chooser scopedCategoryId=2}}', test(assert) { - expandSelectBoxKit(); + expandSelectKit(); andThen(() => { - assert.equal(selectBox('.category-chooser').rowByIndex(0).name(), "feature"); - assert.equal(selectBox('.category-chooser').rowByIndex(1).name(), "spec"); - assert.equal(selectBox('.category-chooser').el.find(".select-box-kit-row").length, 2); + assert.equal(selectKit('.category-chooser').rowByIndex(0).name(), "feature"); + assert.equal(selectKit('.category-chooser').rowByIndex(1).name(), "spec"); + assert.equal(selectKit('.category-chooser').el.find(".select-kit-row").length, 2); }); } }); @@ -48,10 +48,10 @@ componentTest('with allowUncategorized=null', { }, test(assert) { - expandSelectBoxKit(); + expandSelectKit(); andThen(() => { - assert.equal(selectBox('.category-chooser').header.name(), "Select a category…"); + assert.equal(selectKit('.category-chooser').header.name(), "Select a category…"); }); } }); @@ -64,10 +64,10 @@ componentTest('with allowUncategorized=null rootNone=true', { }, test(assert) { - expandSelectBoxKit(); + expandSelectKit(); andThen(() => { - assert.equal(selectBox('.category-chooser').header.name(), "Select a category…"); + assert.equal(selectKit('.category-chooser').header.name(), "Select a category…"); }); } }); @@ -81,10 +81,10 @@ componentTest('with disallowed uncategorized, rootNone and rootNoneLabel', { }, test(assert) { - expandSelectBoxKit(); + expandSelectKit(); andThen(() => { - assert.equal(selectBox('.category-chooser').header.name(), "Select a category…"); + assert.equal(selectKit('.category-chooser').header.name(), "Select a category…"); }); } }); @@ -97,10 +97,10 @@ componentTest('with allowed uncategorized', { }, test(assert) { - expandSelectBoxKit(); + expandSelectKit(); andThen(() => { - assert.equal(selectBox('.category-chooser').header.name(), "uncategorized"); + assert.equal(selectKit('.category-chooser').header.name(), "uncategorized"); }); } }); @@ -113,10 +113,10 @@ componentTest('with allowed uncategorized and rootNone', { }, test(assert) { - expandSelectBoxKit(); + expandSelectKit(); andThen(() => { - assert.equal(selectBox('.category-chooser').header.name(), "(no category)"); + assert.equal(selectKit('.category-chooser').header.name(), "(no category)"); }); } }); @@ -130,10 +130,10 @@ componentTest('with allowed uncategorized rootNone and rootNoneLabel', { }, test(assert) { - expandSelectBoxKit(); + expandSelectKit(); andThen(() => { - assert.equal(selectBox('.category-chooser').header.name(), "root none label"); + assert.equal(selectKit('.category-chooser').header.name(), "root none label"); }); } }); diff --git a/test/javascripts/components/categpry-selector-test.js.es6 b/test/javascripts/components/categpry-selector-test.js.es6 new file mode 100644 index 00000000000..8c0925587eb --- /dev/null +++ b/test/javascripts/components/categpry-selector-test.js.es6 @@ -0,0 +1,67 @@ +import componentTest from 'helpers/component-test'; +import Category from "discourse/models/category"; + +moduleForComponent('category-selector', {integration: true}); + +componentTest('default', { + template: '{{category-selector categories=categories}}', + + beforeEach() { + this.set('categories', [ Category.findById(2) ]); + }, + + test(assert) { + andThen(() => { + assert.propEqual(selectKit().header.name(), 'feature'); + assert.ok(!exists(".select-kit .select-kit-row[data-value='2']"), "selected categories are not in the list"); + }); + } +}); + +componentTest('with blacklist', { + template: '{{category-selector categories=categories blacklist=blacklist}}', + + beforeEach() { + this.set('categories', [ Category.findById(2) ]); + this.set('blacklist', [ Category.findById(8) ]); + }, + + test(assert) { + expandSelectKit(); + + andThen(() => { + assert.ok(exists(".select-kit .select-kit-row[data-value='6']"), "not blacklisted categories are in the list"); + assert.ok(!exists(".select-kit .select-kit-row[data-value='8']"), "blacklisted categories are not in the list"); + }); + } +}); + +componentTest('interactions', { + template: '{{category-selector categories=categories}}', + + beforeEach() { + this.set('categories', [ + Category.findById(2), + Category.findById(6) + ]); + }, + + test(assert) { + expandSelectKit(); + + selectKitSelectRow(8); + + andThen(() => { + assert.propEqual(selectKit().header.name(), 'feature,support,hosting', 'it adds the selected category'); + assert.equal(this.get('categories').length, 3); + }); + + selectKit().keyboard.backspace(); + selectKit().keyboard.backspace(); + + andThen(() => { + assert.propEqual(selectKit().header.name(), 'feature,support', 'it removes the last selected category'); + assert.equal(this.get('categories').length, 2); + }); + } +}); diff --git a/test/javascripts/components/combo-box-test.js.es6 b/test/javascripts/components/combo-box-test.js.es6 index c7f50b5da13..bf1534cf7ce 100644 --- a/test/javascripts/components/combo-box-test.js.es6 +++ b/test/javascripts/components/combo-box-test.js.es6 @@ -8,12 +8,12 @@ componentTest('default', { }, test(assert) { - expandSelectBoxKit(); + expandSelectKit(); andThen(() => { - assert.equal(selectBox('.combobox').header.name(), "hello"); - assert.equal(selectBox('.combobox').rowByValue(1).name(), "hello"); - assert.equal(selectBox('.combobox').rowByValue(2).name(), "world"); + assert.equal(selectKit('.combobox').header.name(), "hello"); + assert.equal(selectKit('.combobox').rowByValue(1).name(), "hello"); + assert.equal(selectKit('.combobox').rowByValue(2).name(), "world"); }); } }); @@ -25,11 +25,11 @@ componentTest('with valueAttribute', { }, test(assert) { - expandSelectBoxKit(); + expandSelectKit(); andThen(() => { - assert.equal(selectBox('.combobox').rowByValue(0).name(), "hello"); - assert.equal(selectBox('.combobox').rowByValue(1).name(), "world"); + assert.equal(selectKit('.combobox').rowByValue(0).name(), "hello"); + assert.equal(selectKit('.combobox').rowByValue(1).name(), "world"); }); } }); @@ -41,11 +41,11 @@ componentTest('with nameProperty', { }, test(assert) { - expandSelectBoxKit(); + expandSelectKit(); andThen(() => { - assert.equal(selectBox('.combobox').rowByValue(0).name(), "hello"); - assert.equal(selectBox('.combobox').rowByValue(1).name(), "world"); + assert.equal(selectKit('.combobox').rowByValue(0).name(), "hello"); + assert.equal(selectKit('.combobox').rowByValue(1).name(), "world"); }); } }); @@ -57,11 +57,11 @@ componentTest('with an array as content', { }, test(assert) { - expandSelectBoxKit(); + expandSelectKit(); andThen(() => { - assert.equal(selectBox('.combobox').rowByValue('evil').name(), "evil"); - assert.equal(selectBox('.combobox').rowByValue('trout').name(), "trout"); + assert.equal(selectKit('.combobox').rowByValue('evil').name(), "evil"); + assert.equal(selectKit('.combobox').rowByValue('trout').name(), "trout"); }); } }); @@ -75,17 +75,17 @@ componentTest('with value and none as a string', { }, test(assert) { - expandSelectBoxKit(); + expandSelectKit(); andThen(() => { - assert.equal(selectBox('.combobox').noneRow.name(), 'none'); - assert.equal(selectBox('.combobox').rowByValue("evil").name(), "evil"); - assert.equal(selectBox('.combobox').rowByValue("trout").name(), "trout"); - assert.equal(selectBox('.combobox').header.name(), 'trout'); + assert.equal(selectKit('.combobox').noneRow.name(), 'none'); + assert.equal(selectKit('.combobox').rowByValue("evil").name(), "evil"); + assert.equal(selectKit('.combobox').rowByValue("trout").name(), "trout"); + assert.equal(selectKit('.combobox').header.name(), 'trout'); assert.equal(this.get('value'), 'trout'); }); - selectBoxKitSelectRow('__none__', {selector: '.combobox' }); + selectKitSelectRow('__none__', {selector: '.combobox' }); andThen(() => { assert.equal(this.get('value'), null); @@ -102,17 +102,17 @@ componentTest('with value and none as an object', { }, test(assert) { - expandSelectBoxKit(); + expandSelectKit(); andThen(() => { - assert.equal(selectBox('.combobox').noneRow.name(), 'none'); - assert.equal(selectBox('.combobox').rowByValue("evil").name(), "evil"); - assert.equal(selectBox('.combobox').rowByValue("trout").name(), "trout"); - assert.equal(selectBox('.combobox').header.name(), 'evil'); + assert.equal(selectKit('.combobox').noneRow.name(), 'none'); + assert.equal(selectKit('.combobox').rowByValue("evil").name(), "evil"); + assert.equal(selectKit('.combobox').rowByValue("trout").name(), "trout"); + assert.equal(selectKit('.combobox').header.name(), 'evil'); assert.equal(this.get('value'), 'evil'); }); - selectBoxKitSelectNoneRow({ selector: '.combobox' }); + selectKitSelectNoneRow({ selector: '.combobox' }); andThen(() => { assert.equal(this.get('value'), null); @@ -130,10 +130,10 @@ componentTest('with no value and none as an object', { }, test(assert) { - expandSelectBoxKit(); + expandSelectKit(); andThen(() => { - assert.equal(selectBox('.combobox').header.name(), 'none'); + assert.equal(selectKit('.combobox').header.name(), 'none'); }); } }); @@ -148,10 +148,10 @@ componentTest('with no value and none string', { }, test(assert) { - expandSelectBoxKit(); + expandSelectKit(); andThen(() => { - assert.equal(selectBox('.combobox').header.name(), 'none'); + assert.equal(selectKit('.combobox').header.name(), 'none'); }); } }); @@ -164,10 +164,10 @@ componentTest('with no value and no none', { }, test(assert) { - expandSelectBoxKit(); + expandSelectKit(); andThen(() => { - assert.equal(selectBox('.combobox').header.name(), 'evil', 'it sets the first row as value'); + assert.equal(selectKit('.combobox').header.name(), 'evil', 'it sets the first row as value'); }); } }); @@ -182,17 +182,17 @@ componentTest('with no value and no none', { // test(assert) { // (); // -// andThen(() => assert.equal(find(".select-box-kit-filter-input").length, 1, "it has a search input")); +// andThen(() => assert.equal(find(".filter-input").length, 1, "it has a search input")); // -// selectBoxKitFillInFilter("regis"); +// selectKitFillInFilter("regis"); // -// andThen(() => assert.equal(selectBox().rows.length, 1, "it filters results")); +// andThen(() => assert.equal(selectKit().rows.length, 1, "it filters results")); // -// selectBoxKitFillInFilter(""); +// selectKitFillInFilter(""); // // andThen(() => { // assert.equal( -// selectBox().rows.length, 2, +// selectKit().rows.length, 2, // "it returns to original content when filter is empty" // ); // }); @@ -209,17 +209,17 @@ componentTest('with no value and no none', { // test(assert) { // (); // -// selectBoxKitFillInFilter("rob"); +// selectKitFillInFilter("rob"); // -// andThen(() => assert.equal(selectBox().rows.length, 1) ); +// andThen(() => assert.equal(selectKit().rows.length, 1) ); // -// collapseSelectBoxKit(); +// collapseSelectKit(); // -// andThen(() => assert.notOk(selectBox().isExpanded) ); +// andThen(() => assert.notOk(selectKit().isExpanded) ); // // (); // -// andThen(() => assert.equal(selectBox().rows.length, 1) ); +// andThen(() => assert.equal(selectKit().rows.length, 1) ); // } // }); @@ -232,10 +232,10 @@ componentTest('with empty string as value', { }, test(assert) { - expandSelectBoxKit(); + expandSelectKit(); andThen(() => { - assert.equal(selectBox('.combobox').header.name(), 'evil', 'it sets the first row as value'); + assert.equal(selectKit('.combobox').header.name(), 'evil', 'it sets the first row as value'); }); } }); diff --git a/test/javascripts/components/d-button-test.js.es6 b/test/javascripts/components/d-button-test.js.es6 index d283da4f21c..e40d47fe851 100644 --- a/test/javascripts/components/d-button-test.js.es6 +++ b/test/javascripts/components/d-button-test.js.es6 @@ -6,7 +6,7 @@ componentTest('icon only button', { test(assert) { assert.ok(this.$('button.btn.btn-icon.no-text').length, 'it has all the classes'); - assert.ok(this.$('button .d-icon.d-icon-plus').length, 'it has the icon'); + assert.ok(this.$('button .d-icon.d-plus').length, 'it has the icon'); assert.equal(this.$('button').attr('tabindex'), "3", 'it has the tabindex'); } }); @@ -16,7 +16,7 @@ componentTest('icon and text button', { test(assert) { assert.ok(this.$('button.btn.btn-icon-text').length, 'it has all the classes'); - assert.ok(this.$('button .d-icon.d-icon-plus').length, 'it has the icon'); + assert.ok(this.$('button .d-icon.d-plus').length, 'it has the icon'); assert.ok(this.$('button span.d-button-label').length, 'it has the label'); } }); diff --git a/test/javascripts/components/list-setting-test.js.es6 b/test/javascripts/components/list-setting-test.js.es6 index c3dd271fb1b..184d86a38d8 100644 --- a/test/javascripts/components/list-setting-test.js.es6 +++ b/test/javascripts/components/list-setting-test.js.es6 @@ -11,10 +11,26 @@ componentTest('default', { }, test(assert) { - expandSelectBoxKit(); + expandSelectKit(); andThen(() => { - assert.propEqual(selectBox().header.name(), 'bold,italic'); + assert.propEqual(selectKit().header.name(), 'bold,italic'); + }); + } +}); + +componentTest('with emptry string as value', { + template: '{{list-setting settingValue=settingValue}}', + + beforeEach() { + this.set('settingValue', ''); + }, + + test(assert) { + expandSelectKit(); + + andThen(() => { + assert.equal(selectKit().header.el.find(".selected-name").length, 0); }); } }); @@ -27,10 +43,10 @@ componentTest('with only setting value', { }, test(assert) { - expandSelectBoxKit(); + expandSelectKit(); andThen(() => { - assert.propEqual(selectBox().header.name(), 'bold,italic'); + assert.propEqual(selectKit().header.name(), 'bold,italic'); }); } }); @@ -44,28 +60,28 @@ componentTest('interactions', { }, test(assert) { - expandSelectBoxKit(); + expandSelectKit(); - selectBoxKitSelectRow('underline'); + selectKitSelectRow('underline'); andThen(() => { - assert.propEqual(selectBox().header.name(), 'bold,italic,underline'); + assert.propEqual(selectKit().header.name(), 'bold,italic,underline'); }); - selectBoxKitFillInFilter('strike'); + selectKitFillInFilter('strike'); andThen(() => { - assert.equal(selectBox().highlightedRow.name(), 'strike'); + assert.equal(selectKit().highlightedRow.name(), 'strike'); }); - selectBox().keyboard.enter(); + selectKit().keyboard.enter(); andThen(() => { - assert.propEqual(selectBox().header.name(), 'bold,italic,underline,strike'); + assert.propEqual(selectKit().header.name(), 'bold,italic,underline,strike'); }); - selectBox().keyboard.backspace(); - selectBox().keyboard.backspace(); + selectKit().keyboard.backspace(); + selectKit().keyboard.backspace(); andThen(() => { assert.equal(this.get('choices').length, 3, 'it removes the created content from original list'); diff --git a/test/javascripts/components/multi-combo-box-test.js.es6 b/test/javascripts/components/multi-combo-box-test.js.es6 deleted file mode 100644 index 81f8b209e70..00000000000 --- a/test/javascripts/components/multi-combo-box-test.js.es6 +++ /dev/null @@ -1,109 +0,0 @@ -import componentTest from 'helpers/component-test'; -moduleForComponent('multi-combo-box', {integration: true}); - -componentTest('with objects and values', { - template: '{{multi-combo-box content=items value=value}}', - - beforeEach() { - this.set('items', [{id: 1, name: 'hello'}, {id: 2, name: 'world'}]); - this.set('value', [1, 2]); - }, - - test(assert) { - andThen(() => { - assert.propEqual(selectBox().header.name(), 'hello,world'); - }); - } -}); - -componentTest('interactions', { - template: '{{multi-combo-box none=none content=items value=value}}', - - beforeEach() { - I18n.translations[I18n.locale].js.test = {none: 'none'}; - this.set('items', [{id: 1, name: 'regis'}, {id: 2, name: 'sam'}, {id: 3, name: 'robin'}]); - this.set('value', [1, 2]); - }, - - test(assert) { - expandSelectBoxKit(); - - andThen(() => { - assert.equal(selectBox().highlightedRow.name(), 'robin', 'it highlights the first content row'); - }); - - this.set('none', 'test.none'); - - andThen(() => { - assert.equal(selectBox().noneRow.el.length, 1); - assert.equal(selectBox().highlightedRow.name(), 'robin', 'it highlights the first content row'); - }); - - selectBoxKitSelectRow(3); - - andThen(() => { - assert.equal(selectBox().highlightedRow.name(), 'none', 'it highlights none row if no content'); - }); - - selectBoxKitFillInFilter('joffrey'); - - andThen(() => { - assert.equal(selectBox().highlightedRow.name(), 'joffrey', 'it highlights create row when filling filter'); - }); - - selectBox().keyboard.enter(); - - andThen(() => { - assert.equal(selectBox().highlightedRow.name(), 'none', 'it highlights none row after creating content and no content left'); - }); - - selectBox().keyboard.backspace(); - - andThen(() => { - const $lastSelectedName = selectBox().header.el.find('.selected-name').last(); - assert.equal($lastSelectedName.attr('data-name'), 'joffrey'); - assert.ok($lastSelectedName.hasClass('is-highlighted'), 'it highlights the last selected name when using backspace'); - }); - - selectBox().keyboard.backspace(); - - andThen(() => { - const $lastSelectedName = selectBox().header.el.find('.selected-name').last(); - assert.equal($lastSelectedName.attr('data-name'), 'robin', 'it removes the previous highlighted selected content'); - assert.notOk(exists(selectBox().rowByValue('joffrey').el), 'generated content shouldn’t appear in content when removed'); - }); - - selectBox().keyboard.selectAll(); - - andThen(() => { - const $highlightedSelectedNames = selectBox().header.el.find('.selected-name.is-highlighted'); - assert.equal($highlightedSelectedNames.length, 3, 'it highlights each selected name'); - }); - - selectBox().keyboard.backspace(); - - andThen(() => { - const $selectedNames = selectBox().header.el.find('.selected-name'); - assert.equal($selectedNames.length, 0, 'it removed all selected content'); - }); - - andThen(() => { - assert.ok(this.$(".select-box-kit").hasClass("is-focused")); - assert.ok(this.$(".select-box-kit").hasClass("is-expanded")); - }); - - selectBox().keyboard.escape(); - - andThen(() => { - assert.ok(this.$(".select-box-kit").hasClass("is-focused")); - assert.notOk(this.$(".select-box-kit").hasClass("is-expanded")); - }); - - selectBox().keyboard.escape(); - - andThen(() => { - assert.notOk(this.$(".select-box-kit").hasClass("is-focused")); - assert.notOk(this.$(".select-box-kit").hasClass("is-expanded")); - }); - } -}); diff --git a/test/javascripts/components/multi-select-test.js.es6 b/test/javascripts/components/multi-select-test.js.es6 new file mode 100644 index 00000000000..f1c95b17ec2 --- /dev/null +++ b/test/javascripts/components/multi-select-test.js.es6 @@ -0,0 +1,109 @@ +import componentTest from 'helpers/component-test'; +moduleForComponent('multi-select', {integration: true}); + +componentTest('with objects and values', { + template: '{{multi-select content=items values=values}}', + + beforeEach() { + this.set('items', [{id: 1, name: 'hello'}, {id: 2, name: 'world'}]); + this.set('values', [1, 2]); + }, + + test(assert) { + andThen(() => { + assert.propEqual(selectKit().header.name(), 'hello,world'); + }); + } +}); + +componentTest('interactions', { + template: '{{multi-select none=none content=items values=values}}', + + beforeEach() { + I18n.translations[I18n.locale].js.test = {none: 'none'}; + this.set('items', [{id: 1, name: 'regis'}, {id: 2, name: 'sam'}, {id: 3, name: 'robin'}]); + this.set('values', [1, 2]); + }, + + test(assert) { + expandSelectKit(); + + andThen(() => { + assert.equal(selectKit().highlightedRow.name(), 'robin', 'it highlights the first content row'); + }); + + this.set('none', 'test.none'); + + andThen(() => { + assert.equal(selectKit().noneRow.el.length, 1); + assert.equal(selectKit().highlightedRow.name(), 'robin', 'it highlights the first content row'); + }); + + selectKitSelectRow(3); + + andThen(() => { + assert.equal(selectKit().highlightedRow.name(), 'none', 'it highlights none row if no content'); + }); + + selectKitFillInFilter('joffrey'); + + andThen(() => { + assert.equal(selectKit().highlightedRow.name(), 'joffrey', 'it highlights create row when filling filter'); + }); + + selectKit().keyboard.enter(); + + andThen(() => { + assert.equal(selectKit().highlightedRow.name(), 'none', 'it highlights none row after creating content and no content left'); + }); + + selectKit().keyboard.backspace(); + + andThen(() => { + const $lastSelectedName = selectKit().header.el.find('.selected-name').last(); + assert.equal($lastSelectedName.attr('data-name'), 'joffrey'); + assert.ok($lastSelectedName.hasClass('is-highlighted'), 'it highlights the last selected name when using backspace'); + }); + + selectKit().keyboard.backspace(); + + andThen(() => { + const $lastSelectedName = selectKit().header.el.find('.selected-name').last(); + assert.equal($lastSelectedName.attr('data-name'), 'robin', 'it removes the previous highlighted selected content'); + assert.notOk(exists(selectKit().rowByValue('joffrey').el), 'generated content shouldn’t appear in content when removed'); + }); + + selectKit().keyboard.selectAll(); + + andThen(() => { + const $highlightedSelectedNames = selectKit().header.el.find('.selected-name.is-highlighted'); + assert.equal($highlightedSelectedNames.length, 3, 'it highlights each selected name'); + }); + + selectKit().keyboard.backspace(); + + andThen(() => { + const $selectedNames = selectKit().header.el.find('.selected-name'); + assert.equal($selectedNames.length, 0, 'it removed all selected content'); + }); + + andThen(() => { + assert.ok(this.$(".select-kit").hasClass("is-focused")); + assert.ok(this.$(".select-kit").hasClass("is-expanded")); + }); + + selectKit().keyboard.escape(); + + andThen(() => { + assert.ok(this.$(".select-kit").hasClass("is-focused")); + assert.notOk(this.$(".select-kit").hasClass("is-expanded")); + }); + + selectKit().keyboard.escape(); + + andThen(() => { + assert.notOk(this.$(".select-kit").hasClass("is-focused")); + assert.notOk(this.$(".select-kit").hasClass("is-expanded")); + }); + } +}); diff --git a/test/javascripts/components/pinned-button-test.js.es6 b/test/javascripts/components/pinned-button-test.js.es6 deleted file mode 100644 index 154d321a23c..00000000000 --- a/test/javascripts/components/pinned-button-test.js.es6 +++ /dev/null @@ -1,40 +0,0 @@ -import componentTest from 'helpers/component-test'; -import Topic from 'discourse/models/topic'; - -const buildTopic = function() { - return Topic.create({ - id: 1234, - title: "Qunit Test Topic", - deleted: false, - pinned: true - }); -}; - -moduleForComponent('pinned-button', { integration: true }); - -componentTest('updating the content refreshes the list', { - template: '{{pinned-button topic=topic}}', - - beforeEach() { - this.siteSettings.automatically_unpin_topics = false; - this.set("topic", buildTopic()); - }, - - test(assert) { - andThen(() => assert.notOk(selectBox().isHidden) ); - - expandSelectBoxKit(); - - andThen(() => assert.equal(selectBox().selectedRow.name(), "Pinned") ); - - andThen(() => { - this.set("topic.pinned", false); - assert.equal(selectBox().selectedRow.name(), "Unpinned"); - }); - - andThen(() => { - this.set("topic.deleted", true); - assert.ok(find(".pinned-button").hasClass("is-hidden"), "it hides the button when topic is deleted"); - }); - } -}); diff --git a/test/javascripts/components/pinned-options-test.js.es6 b/test/javascripts/components/pinned-options-test.js.es6 new file mode 100644 index 00000000000..3808b63dca9 --- /dev/null +++ b/test/javascripts/components/pinned-options-test.js.es6 @@ -0,0 +1,35 @@ +import componentTest from 'helpers/component-test'; +import Topic from 'discourse/models/topic'; + +const buildTopic = function() { + return Topic.create({ + id: 1234, + title: "Qunit Test Topic", + deleted: false, + pinned: true + }); +}; + +moduleForComponent('pinned-options', { integration: true }); + +componentTest('updating the content refreshes the list', { + template: '{{pinned-options value=pinned topic=topic}}', + + beforeEach() { + this.siteSettings.automatically_unpin_topics = false; + this.set("topic", buildTopic()); + this.set("pinned", true); + }, + + test(assert) { + expandSelectKit(); + + andThen(() => assert.equal(selectKit().header.name(), "Pinned") ); + + andThen(() => this.set("pinned", false)); + + andThen(() => { + assert.equal(selectKit().header.name(), "Unpinned"); + }); + } +}); diff --git a/test/javascripts/components/select-box-kit-test.js.es6 b/test/javascripts/components/select-box-kit-test.js.es6 deleted file mode 100644 index 904684cd8b7..00000000000 --- a/test/javascripts/components/select-box-kit-test.js.es6 +++ /dev/null @@ -1,288 +0,0 @@ -import componentTest from 'helpers/component-test'; - -moduleForComponent('select-box-kit', { integration: true }); - -componentTest('updating the content refreshes the list', { - template: '{{select-box-kit value=1 content=content}}', - - beforeEach() { - this.set("content", [{ id: 1, name: "robin" }]); - }, - - test(assert) { - expandSelectBoxKit(); - - andThen(() => { - assert.equal(selectBox().rowByValue(1).name(), "robin"); - this.set("content", [{ id: 1, name: "regis" }]); - assert.equal(selectBox().rowByValue(1).name(), "regis"); - }); - } -}); - -componentTest('accepts a value by reference', { - template: '{{select-box-kit value=value content=content}}', - - beforeEach() { - this.set("value", 1); - this.set("content", [{ id: 1, name: "robin" }, { id: 2, name: "regis" }]); - }, - - test(assert) { - expandSelectBoxKit(); - - andThen(() => { - assert.equal( - selectBox().selectedRow.name(), "robin", - "it highlights the row corresponding to the value" - ); - }); - - selectBoxKitSelectRow(1); - - andThen(() => { - assert.equal(this.get("value"), 1, "it mutates the value"); - }); - } -}); - -componentTest('no default icon', { - template: '{{select-box-kit}}', - - test(assert) { - assert.equal(selectBox().header.icon().length, 0, "it doesn’t have an icon if not specified"); - } -}); - -componentTest('default search icon', { - template: '{{select-box-kit filterable=true}}', - - test(assert) { - expandSelectBoxKit(); - - andThen(() => { - assert.ok(exists(selectBox().filter.icon), "it has a the correct icon"); - }); - } -}); - -componentTest('with no search icon', { - template: '{{select-box-kit filterable=true filterIcon=null}}', - - test(assert) { - expandSelectBoxKit(); - - andThen(() => { - assert.equal(selectBox().filter.icon().length, 0, "it has no icon"); - }); - } -}); - -componentTest('custom search icon', { - template: '{{select-box-kit filterable=true filterIcon="shower"}}', - - test(assert) { - expandSelectBoxKit(); - - andThen(() => { - assert.ok(selectBox().filter.icon().hasClass("d-icon-shower"), "it has a the correct icon"); - }); - } -}); - -componentTest('select-box is expandable', { - template: '{{select-box-kit}}', - test(assert) { - expandSelectBoxKit(); - - andThen(() => assert.ok(selectBox().isExpanded) ); - - collapseSelectBoxKit(); - - andThen(() => assert.notOk(selectBox().isExpanded) ); - } -}); - -componentTest('accepts custom value/name keys', { - template: '{{select-box-kit value=value nameProperty="item" content=content valueAttribute="identifier"}}', - - beforeEach() { - this.set("value", 1); - this.set("content", [{ identifier: 1, item: "robin" }]); - }, - - test(assert) { - expandSelectBoxKit(); - - andThen(() => { - assert.equal(selectBox().selectedRow.name(), "robin"); - }); - } -}); - -componentTest('doesn’t render collection content before first expand', { - template: '{{select-box-kit value=1 content=content}}', - - beforeEach() { - this.set("content", [{ value: 1, name: "robin" }]); - }, - - test(assert) { - assert.notOk(exists(find(".select-box-kit-collection"))); - - expandSelectBoxKit(); - - andThen(() => { - assert.ok(exists(find(".select-box-kit-collection"))); - }); - } -}); - -componentTest('supports options to limit size', { - template: '{{select-box-kit collectionHeight=20 content=content}}', - - beforeEach() { - this.set("content", ["robin", "régis"]); - }, - - test(assert) { - expandSelectBoxKit(); - - andThen(() => { - const height = find(".select-box-kit-collection").height(); - assert.equal(parseInt(height, 10), 20, "it limits the height"); - }); - } -}); - -componentTest('dynamic headerText', { - template: '{{select-box-kit value=1 content=content}}', - - beforeEach() { - this.set("content", [{ id: 1, name: "robin" }, { id: 2, name: "regis" }]); - }, - - test(assert) { - expandSelectBoxKit(); - - andThen(() => assert.equal(selectBox().header.name(), "robin") ); - - selectBoxKitSelectRow(2); - - andThen(() => { - assert.equal(selectBox().header.name(), "regis", "it changes header text"); - }); - } -}); - -componentTest('supports custom row template', { - template: '{{select-box-kit content=content templateForRow=templateForRow}}', - - beforeEach() { - this.set("content", [{ id: 1, name: "robin" }]); - this.set("templateForRow", rowComponent => { - return `${rowComponent.get("content.name")}`; - }); - }, - - test(assert) { - expandSelectBoxKit(); - - andThen(() => assert.equal(selectBox().rowByValue(1).el.html().trim(), "robin") ); - } -}); - -componentTest('supports converting select value to integer', { - template: '{{select-box-kit value=value content=content castInteger=true}}', - - beforeEach() { - this.set("value", 2); - this.set("content", [{ id: "1", name: "robin"}, {id: "2", name: "régis" }]); - }, - - test(assert) { - expandSelectBoxKit(); - - andThen(() => assert.equal(selectBox().selectedRow.name(), "régis") ); - - andThen(() => { - this.set("value", 3); - this.set("content", [{ id: "3", name: "jeff" }]); - }); - - andThen(() => { - assert.equal(selectBox().selectedRow.name(), "jeff", "it works with dynamic content"); - }); - } -}); - -componentTest('supports keyboard events', { - template: '{{select-box-kit content=content filterable=true}}', - - beforeEach() { - this.set("content", [{ id: 1, name: "robin" }, { id: 2, name: "regis" }]); - }, - - test(assert) { - expandSelectBoxKit(); - - selectBox().keyboard.down(); - - andThen(() => { - assert.equal(selectBox().highlightedRow.title(), "regis", "the next row is highlighted"); - }); - - selectBox().keyboard.down(); - - andThen(() => { - assert.equal(selectBox().highlightedRow.title(), "robin", "it returns to the first row"); - }); - - selectBox().keyboard.up(); - - andThen(() => { - assert.equal(selectBox().highlightedRow.title(), "regis", "it highlights the last row"); - }); - - selectBox().keyboard.enter(); - - andThen(() => { - assert.equal(selectBox().selectedRow.title(), "regis", "it selects the row when pressing enter"); - assert.notOk(selectBox().isExpanded, "it collapses the select box when selecting a row"); - }); - - expandSelectBoxKit(); - - selectBox().keyboard.escape(); - - andThen(() => { - assert.notOk(selectBox().isExpanded, "it collapses the select box"); - }); - - expandSelectBoxKit(); - - selectBoxKitFillInFilter("regis"); - - selectBox().keyboard.tab(); - - andThen(() => { - assert.notOk(selectBox().isExpanded, "it collapses the select box when selecting a row"); - }); - } -}); - - -componentTest('supports mutating value when no value given', { - template: '{{select-box-kit value=value content=content}}', - - beforeEach() { - this.set("value", ""); - this.set("content", [{ id: "1", name: "robin"}, {id: "2", name: "régis" }]); - }, - - test(assert) { - andThen(() => { - assert.equal(this.get("value"), "1"); - }); - } -}); diff --git a/test/javascripts/components/single-select-test.js.es6 b/test/javascripts/components/single-select-test.js.es6 new file mode 100644 index 00000000000..ca066907625 --- /dev/null +++ b/test/javascripts/components/single-select-test.js.es6 @@ -0,0 +1,372 @@ +import componentTest from 'helpers/component-test'; +import { withPluginApi } from 'discourse/lib/plugin-api'; +import { clearCallbacks } from 'select-kit/mixins/plugin-api'; + +moduleForComponent('single-select', { integration: true }); + +componentTest('updating the content refreshes the list', { + template: '{{single-select value=1 content=content}}', + + beforeEach() { + this.set("content", [{ id: 1, name: "BEFORE" }]); + }, + + test(assert) { + expandSelectKit(); + + andThen(() => { + assert.equal(selectKit().rowByValue(1).name(), "BEFORE"); + }); + + andThen(() => { + this.set("content", [{ id: 1, name: "AFTER" }]); + }); + + andThen(() => { + assert.equal(selectKit().rowByValue(1).name(), "AFTER"); + }); + } +}); + +componentTest('accepts a value by reference', { + template: '{{single-select value=value content=content}}', + + beforeEach() { + this.set("value", 1); + this.set("content", [{ id: 1, name: "robin" }, { id: 2, name: "regis" }]); + }, + + test(assert) { + expandSelectKit(); + + andThen(() => { + assert.equal( + selectKit().selectedRow.name(), "robin", + "it highlights the row corresponding to the value" + ); + }); + + selectKitSelectRow(1); + + andThen(() => { + assert.equal(this.get("value"), 1, "it mutates the value"); + }); + } +}); + +componentTest('no default icon', { + template: '{{single-select}}', + + test(assert) { + assert.equal(selectKit().header.icon().length, 0, "it doesn’t have an icon if not specified"); + } +}); + +componentTest('default search icon', { + template: '{{single-select filterable=true}}', + + test(assert) { + expandSelectKit(); + + andThen(() => { + assert.ok(exists(selectKit().filter.icon), "it has a the correct icon"); + }); + } +}); + +componentTest('with no search icon', { + template: '{{single-select filterable=true filterIcon=null}}', + + test(assert) { + expandSelectKit(); + + andThen(() => { + assert.equal(selectKit().filter.icon().length, 0, "it has no icon"); + }); + } +}); + +componentTest('custom search icon', { + template: '{{single-select filterable=true filterIcon="shower"}}', + + test(assert) { + expandSelectKit(); + + andThen(() => { + assert.ok(selectKit().filter.icon().hasClass("fa-shower"), "it has a the correct icon"); + }); + } +}); + +componentTest('is expandable', { + template: '{{single-select}}', + test(assert) { + expandSelectKit(); + + andThen(() => assert.ok(selectKit().isExpanded) ); + + collapseSelectKit(); + + andThen(() => assert.notOk(selectKit().isExpanded) ); + } +}); + +componentTest('accepts custom value/name keys', { + template: '{{single-select value=value nameProperty="item" content=content valueAttribute="identifier"}}', + + beforeEach() { + this.set("value", 1); + this.set("content", [{ identifier: 1, item: "robin" }]); + }, + + test(assert) { + expandSelectKit(); + + andThen(() => { + assert.equal(selectKit().selectedRow.name(), "robin"); + }); + } +}); + +componentTest('doesn’t render collection content before first expand', { + template: '{{single-select value=1 content=content}}', + + beforeEach() { + this.set("content", [{ value: 1, name: "robin" }]); + }, + + test(assert) { + assert.notOk(exists(find(".select-kit-collection"))); + + expandSelectKit(); + + andThen(() => { + assert.ok(exists(find(".select-kit-collection"))); + }); + } +}); + +componentTest('supports options to limit size', { + template: '{{single-select collectionHeight=20 content=content}}', + + beforeEach() { + this.set("content", ["robin", "régis"]); + }, + + test(assert) { + expandSelectKit(); + + andThen(() => { + const height = find(".select-kit-collection").height(); + assert.equal(parseInt(height, 10), 20, "it limits the height"); + }); + } +}); + +componentTest('dynamic headerText', { + template: '{{single-select value=1 content=content}}', + + beforeEach() { + this.set("content", [{ id: 1, name: "robin" }, { id: 2, name: "regis" }]); + }, + + test(assert) { + expandSelectKit(); + + andThen(() => { + assert.equal(selectKit().header.name(), "robin"); + }); + + selectKitSelectRow(2); + + andThen(() => { + assert.equal(selectKit().header.name(), "regis", "it changes header text"); + }); + } +}); + +componentTest('supports custom row template', { + template: '{{single-select content=content templateForRow=templateForRow}}', + + beforeEach() { + this.set("content", [{ id: 1, name: "robin" }]); + this.set("templateForRow", rowComponent => { + return `${rowComponent.get("computedContent.name")}`; + }); + }, + + test(assert) { + expandSelectKit(); + + andThen(() => assert.equal(selectKit().rowByValue(1).el.html().trim(), "robin") ); + } +}); + +componentTest('supports converting select value to integer', { + template: '{{single-select value=value content=content castInteger=true}}', + + beforeEach() { + this.set("value", 2); + this.set("content", [{ id: "1", name: "robin"}, {id: "2", name: "régis" }]); + }, + + test(assert) { + expandSelectKit(); + + andThen(() => assert.equal(selectKit().selectedRow.name(), "régis") ); + + andThen(() => { + this.set("value", 3); + this.set("content", [{ id: "3", name: "jeff" }]); + }); + + andThen(() => { + assert.equal(selectKit().selectedRow.name(), "jeff", "it works with dynamic content"); + }); + } +}); + +componentTest('supports keyboard events', { + template: '{{single-select content=content filterable=true}}', + + beforeEach() { + this.set("content", [{ id: 1, name: "robin" }, { id: 2, name: "regis" }]); + }, + + test(assert) { + expandSelectKit(); + + selectKit().keyboard.down(); + + andThen(() => { + assert.equal(selectKit().highlightedRow.title(), "regis", "the next row is highlighted"); + }); + + selectKit().keyboard.down(); + + andThen(() => { + assert.equal(selectKit().highlightedRow.title(), "robin", "it returns to the first row"); + }); + + selectKit().keyboard.up(); + + andThen(() => { + assert.equal(selectKit().highlightedRow.title(), "regis", "it highlights the last row"); + }); + + selectKit().keyboard.enter(); + + andThen(() => { + assert.equal(selectKit().selectedRow.title(), "regis", "it selects the row when pressing enter"); + assert.notOk(selectKit().isExpanded, "it collapses the select box when selecting a row"); + }); + + expandSelectKit(); + + selectKit().keyboard.escape(); + + andThen(() => { + assert.notOk(selectKit().isExpanded, "it collapses the select box"); + }); + + expandSelectKit(); + + selectKitFillInFilter("regis"); + + selectKit().keyboard.tab(); + + andThen(() => { + assert.notOk(selectKit().isExpanded, "it collapses the select box when selecting a row"); + }); + } +}); + + +componentTest('supports mutating value when no value given', { + template: '{{single-select value=value content=content}}', + + beforeEach() { + this.set("value", ""); + this.set("content", [{ id: "1", name: "robin"}, {id: "2", name: "régis" }]); + }, + + test(assert) { + andThen(() => { + assert.equal(this.get("value"), "1"); + }); + } +}); + +componentTest('support appending content through plugin api', { + template: '{{single-select content=content}}', + + beforeEach() { + withPluginApi('0.8.11', api => { + api.modifySelectKit("select-kit") + .appendContent([{ id: "2", name: "regis"}]); + }); + + this.set("content", [{ id: "1", name: "robin"}]); + }, + test(assert) { + expandSelectKit(); + + andThen(() => { + assert.equal(selectKit().rows.length, 2); + assert.equal(selectKit().rows.eq(1).data("name"), "regis"); + }); + + clearCallbacks(); + } +}); + +componentTest('support modifying content through plugin api', { + template: '{{single-select content=content}}', + + beforeEach() { + withPluginApi('0.8.11', api => { + api.modifySelectKit("select-kit") + .modifyContent((existingContent) => { + existingContent.splice(1, 0, { id: "2", name: "sam" }); + return existingContent; + }); + }); + + this.set("content", [{ id: "1", name: "robin"}, { id: "3", name: "regis"}]); + }, + + test(assert) { + expandSelectKit(); + + andThen(() => { + assert.equal(selectKit().rows.length, 3); + assert.equal(selectKit().rows.eq(1).data("name"), "sam"); + }); + + clearCallbacks(); + } +}); + +componentTest('support prepending content through plugin api', { + template: '{{single-select content=content}}', + + beforeEach() { + withPluginApi('0.8.11', api => { + api.modifySelectKit("select-kit") + .prependContent([{ id: "2", name: "regis"}]); + }); + + this.set("content", [{ id: "1", name: "robin"}]); + }, + + test(assert) { + expandSelectKit(); + + andThen(() => { + assert.equal(selectKit().rows.length, 2); + assert.equal(selectKit().rows.eq(0).data("name"), "regis"); + }); + + clearCallbacks(); + } +}); diff --git a/test/javascripts/components/topic-footer-mobile-dropdown-test.js.es6 b/test/javascripts/components/topic-footer-mobile-dropdown-test.js.es6 index 899bff4545a..9a5534c3cb4 100644 --- a/test/javascripts/components/topic-footer-mobile-dropdown-test.js.es6 +++ b/test/javascripts/components/topic-footer-mobile-dropdown-test.js.es6 @@ -17,16 +17,16 @@ componentTest('default', { }, test(assert) { - expandSelectBoxKit(); + expandSelectKit(); andThen(() => { - assert.equal(selectBox().header.name(), "Topic Controls"); - assert.equal(selectBox().rowByIndex(0).name(), "Bookmark"); - assert.equal(selectBox().rowByIndex(1).name(), "Share"); - assert.equal(selectBox().selectedRow.el.length, 0, "it doesn’t preselect first row"); + assert.equal(selectKit().header.name(), "Topic Controls"); + assert.equal(selectKit().rowByIndex(0).name(), "Bookmark"); + assert.equal(selectKit().rowByIndex(1).name(), "Share"); + assert.equal(selectKit().selectedRow.el.length, 0, "it doesn’t preselect first row"); }); - selectBoxKitSelectRow("share"); + selectKitSelectRow("share"); andThen(() => { assert.equal(this.get("value"), null, "it resets the value"); diff --git a/test/javascripts/components/topic-notifications-button-test.js.es6 b/test/javascripts/components/topic-notifications-button-test.js.es6 index 67fd3ad70ec..0d41471e31a 100644 --- a/test/javascripts/components/topic-notifications-button-test.js.es6 +++ b/test/javascripts/components/topic-notifications-button-test.js.es6 @@ -1,34 +1,34 @@ import componentTest from 'helpers/component-test'; import Topic from 'discourse/models/topic'; -const buildTopic = function() { +const buildTopic = function(level) { return Topic.create({ id: 4563, title: "Qunit Test Topic", details: { - notification_level: 1 + notification_level: level } }); }; - moduleForComponent('topic-notifications-button', { integration: true }); componentTest('the header has a localized title', { - template: '{{topic-notifications-button topic=topic}}', + template: '{{topic-notifications-button notificationLevel=topic.details.notification_level topic=topic}}', beforeEach() { - this.set("topic", buildTopic()); + this.set("topic", buildTopic(1)); }, test(assert) { andThen(() => { - assert.equal(selectBox().header.name(), "Normal", "it has the correct title"); + assert.equal(selectKit().header.name(), "Normal", "it has the correct title"); }); + this.set("topic", buildTopic(2)); + andThen(() => { - this.set("topic.details.notification_level", 2); - assert.equal(selectBox().header.name(), "Tracking", "it correctly changes the title"); + assert.equal(selectKit().header.name(), "Tracking", "it correctly changes the title"); }); } }); diff --git a/test/javascripts/helpers/select-box-kit-helper.js b/test/javascripts/helpers/select-box-kit-helper.js deleted file mode 100644 index 6388cff899d..00000000000 --- a/test/javascripts/helpers/select-box-kit-helper.js +++ /dev/null @@ -1,146 +0,0 @@ -function checkSelectBoxIsNotExpanded(selectBoxSelector) { - if (find(selectBoxSelector).hasClass('is-expanded')) { - throw 'You expected select-box to be collapsed but it is expanded.'; - } -} - -function checkSelectBoxIsNotCollapsed(selectBoxSelector) { - if (!find(selectBoxSelector).hasClass('is-expanded')) { - throw 'You expected select-box to be expanded but it is collapsed.'; - } -} - -Ember.Test.registerAsyncHelper('expandSelectBoxKit', function(app, selectBoxSelector) { - selectBoxSelector = selectBoxSelector || '.select-box-kit'; - - checkSelectBoxIsNotExpanded(selectBoxSelector); - - click(selectBoxSelector + ' .select-box-kit-header'); -}); - -Ember.Test.registerAsyncHelper('collapseSelectBoxKit', function(app, selectBoxSelector) { - selectBoxSelector = selectBoxSelector || '.select-box-kit'; - - checkSelectBoxIsNotCollapsed(selectBoxSelector); - - click(selectBoxSelector + ' .select-box-kit-header'); -}); - -Ember.Test.registerAsyncHelper('selectBoxKitSelectRow', function(app, rowValue, options) { - options = options || {}; - options.selector = options.selector || '.select-box-kit'; - - checkSelectBoxIsNotCollapsed(options.selector); - - click(options.selector + " .select-box-kit-row[data-value='" + rowValue + "']"); -}); - -Ember.Test.registerAsyncHelper('selectBoxKitSelectNoneRow', function(app, options) { - options = options || {}; - options.selector = options.selector || '.select-box-kit'; - - checkSelectBoxIsNotCollapsed(options.selector); - - click(options.selector + " .select-box-kit-row.none"); -}); - -Ember.Test.registerAsyncHelper('selectBoxKitFillInFilter', function(app, filter, options) { - options = options || {}; - options.selector = options.selector || '.select-box-kit'; - - checkSelectBoxIsNotCollapsed(options.selector); - - var filterQuerySelector = options.selector + ' .select-box-kit-filter-input'; - fillIn(filterQuerySelector, filter); -}); - -function selectBox(selector) { // eslint-disable-line no-unused-vars - selector = selector || '.select-box-kit'; - - function rowHelper(row) { - return { - name: function() { return row.attr('data-name'); }, - icon: function() { return row.find('.d-icon'); }, - title: function() { return row.attr('title'); }, - value: function() { return row.attr('data-value'); }, - el: row - }; - } - - function headerHelper(header) { - return { - name: function() { - return header.attr('data-name'); - }, - icon: function() { return header.find('.icon'); }, - title: function() { return header.attr('title'); }, - el: header - }; - } - - function filterHelper(filter) { - return { - icon: function() { return filter.find('.d-icon'); }, - exists: function() { return exists(filter); }, - el: filter - }; - } - - function keyboardHelper() { - function createEvent(target, keyCode, options) { - target = target || ".select-box-kit-filter-input"; - selector = find(selector).find(target); - - andThen(function() { - var event = jQuery.Event(options.type); - event.keyCode = keyCode; - if (options && options.metaKey === true) { event.metaKey = true; } - find(selector).trigger(event); - }); - } - - return { - down: function(target) { createEvent(target, 40, {type: 'keydown'}); }, - up: function(target) { createEvent(target, 38, {type: 'keydown'}); }, - escape: function(target) { createEvent(target, 27, {type: 'keydown'}); }, - enter: function(target) { createEvent(target, 13, {type: 'keypress'}); }, - tab: function(target) { createEvent(target, 9, {type: 'keydown'}); }, - backspace: function(target) { createEvent(target, 8, {type: 'keydown'}); }, - selectAll: function(target) { createEvent(target, 65, {metaKey: true, type: 'keydown'}); }, - }; - } - - return { - keyboard: keyboardHelper(), - - isExpanded: find(selector).hasClass('is-expanded'), - - isHidden: find(selector).hasClass('is-hidden'), - - header: headerHelper(find(selector).find('.select-box-kit-header')), - - filter: filterHelper(find(selector).find('.select-box-kit-filter')), - - rows: find(selector).find('.select-box-kit-row'), - - rowByValue: function(value) { - return rowHelper(find(selector).find('.select-box-kit-row[data-value="' + value + '"]')); - }, - - rowByName: function(name) { - return rowHelper(find(selector).find('.select-box-kit-row[data-name="' + name + '"]')); - }, - - rowByIndex: function(index) { - return rowHelper(find(selector).find('.select-box-kit-row:eq(' + index + ')')); - }, - - el: find(selector), - - noneRow: rowHelper(find(selector).find('.select-box-kit-row.none')), - - selectedRow: rowHelper(find(selector).find('.select-box-kit-row.is-selected')), - - highlightedRow: rowHelper(find(selector).find('.select-box-kit-row.is-highlighted')) - }; -} diff --git a/test/javascripts/helpers/select-kit-helper.js b/test/javascripts/helpers/select-kit-helper.js new file mode 100644 index 00000000000..80c63736063 --- /dev/null +++ b/test/javascripts/helpers/select-kit-helper.js @@ -0,0 +1,149 @@ +function checkSelectKitIsNotExpanded(selector) { + if (find(selector).hasClass('is-expanded')) { + throw 'You expected select-kit to be collapsed but it is expanded.'; + } +} + +function checkSelectKitIsNotCollapsed(selector) { + if (!find(selector).hasClass('is-expanded')) { + throw 'You expected select-kit to be expanded but it is collapsed.'; + } +} + +Ember.Test.registerAsyncHelper('expandSelectKit', function(app, selector) { + selector = selector || '.select-kit'; + + checkSelectKitIsNotExpanded(selector); + + click(selector + ' .select-kit-header'); +}); + +Ember.Test.registerAsyncHelper('collapseSelectKit', function(app, selector) { + selector = selector || '.select-kit'; + + checkSelectKitIsNotCollapsed(selector); + + click(selector + ' .select-kit-header'); +}); + +Ember.Test.registerAsyncHelper('selectKitSelectRow', function(app, rowValue, options) { + options = options || {}; + options.selector = options.selector || '.select-kit'; + + checkSelectKitIsNotCollapsed(options.selector); + + click(options.selector + " .select-kit-row[data-value='" + rowValue + "']"); +}); + +Ember.Test.registerAsyncHelper('selectKitSelectNoneRow', function(app, options) { + options = options || {}; + options.selector = options.selector || '.select-kit'; + + checkSelectKitIsNotCollapsed(options.selector); + + click(options.selector + " .select-kit-row.none"); +}); + +Ember.Test.registerAsyncHelper('selectKitFillInFilter', function(app, filter, options) { + options = options || {}; + options.selector = options.selector || '.select-kit'; + + checkSelectKitIsNotCollapsed(options.selector); + + var filterQuerySelector = options.selector + ' .filter-input'; + fillIn(filterQuerySelector, filter); + +}); + +function selectKit(selector) { // eslint-disable-line no-unused-vars + selector = selector || '.select-kit'; + + function rowHelper(row) { + return { + name: function() { return row.attr('data-name'); }, + icon: function() { return row.find('.d-icon'); }, + title: function() { return row.attr('title'); }, + value: function() { return row.attr('data-value'); }, + el: row + }; + } + + function headerHelper(header) { + return { + name: function() { + return header.attr('data-name'); + }, + icon: function() { return header.find('.icon'); }, + title: function() { return header.attr('title'); }, + el: header + }; + } + + function filterHelper(filter) { + return { + icon: function() { return filter.find('.d-icon'); }, + exists: function() { return exists(filter); }, + el: filter + }; + } + + function keyboardHelper() { + function createEvent(target, keyCode, options) { + target = target || ".filter-input"; + selector = find(selector).find(target); + options = options || {}; + + andThen(function() { + var type = options.type || 'keydown'; + var event = jQuery.Event(type); + event.keyCode = keyCode; + if (options && options.metaKey === true) { event.metaKey = true; } + find(selector).trigger(event); + }); + } + + return { + down: function(target) { createEvent(target, 40); }, + up: function(target) { createEvent(target, 38); }, + escape: function(target) { createEvent(target, 27); }, + enter: function(target) { createEvent(target, 13); }, + tab: function(target) { createEvent(target, 9); }, + backspace: function(target) { createEvent(target, 8); }, + selectAll: function(target) { createEvent(target, 65, {metaKey: true}); }, + }; + } + + return { + keyboard: keyboardHelper(), + + isExpanded: find(selector).hasClass('is-expanded'), + + isHidden: find(selector).hasClass('is-hidden'), + + header: headerHelper(find(selector).find('.select-kit-header')), + + filter: filterHelper(find(selector).find('.select-kit-filter')), + + rows: find(selector).find('.select-kit-row'), + + rowByValue: function(value) { + return rowHelper(find(selector).find('.select-kit-row[data-value="' + value + '"]')); + }, + + rowByName: function(name) { + return rowHelper(find(selector).find('.select-kit-row[data-name="' + name + '"]')); + }, + + rowByIndex: function(index) { + return rowHelper(find(selector).find('.select-kit-row:eq(' + index + ')')); + }, + + el: find(selector), + + noneRow: rowHelper(find(selector).find('.select-kit-row.none')), + + selectedRow: rowHelper(find(selector).find('.select-kit-row.is-selected')), + + highlightedRow: rowHelper(find(selector).find('.select-kit-row.is-highlighted')) + }; +} diff --git a/test/javascripts/test_helper.js b/test/javascripts/test_helper.js index df242fa34ed..83716217317 100644 --- a/test/javascripts/test_helper.js +++ b/test/javascripts/test_helper.js @@ -32,7 +32,7 @@ //= require sinon-qunit-1.0.0 //= require helpers/assertions -//= require helpers/select-box-kit-helper +//= require helpers/select-kit-helper //= require helpers/qunit-helpers //= require_tree ./fixtures diff --git a/test/javascripts/widgets/actions-summary-test.js.es6 b/test/javascripts/widgets/actions-summary-test.js.es6 index f4eb8b78821..2115d79cf78 100644 --- a/test/javascripts/widgets/actions-summary-test.js.es6 +++ b/test/javascripts/widgets/actions-summary-test.js.es6 @@ -74,7 +74,7 @@ widgetTest('post deleted', { }); }, test(assert) { - assert.ok(this.$('.post-action .d-icon-trash-o').length === 1, 'it has the deleted icon'); + assert.ok(this.$('.post-action .d-trash-o').length === 1, 'it has the deleted icon'); assert.ok(this.$('.avatar[title=eviltrout]').length === 1, 'it has the deleted by avatar'); } }); diff --git a/test/javascripts/widgets/button-test.js.es6 b/test/javascripts/widgets/button-test.js.es6 index 96bd4b245c7..afe75224448 100644 --- a/test/javascripts/widgets/button-test.js.es6 +++ b/test/javascripts/widgets/button-test.js.es6 @@ -11,7 +11,7 @@ widgetTest('icon only button', { test(assert) { assert.ok(this.$('button.btn.btn-icon.no-text').length, 'it has all the classes'); - assert.ok(this.$('button .d-icon.d-icon-smile-o').length, 'it has the icon'); + assert.ok(this.$('button .d-icon.d-smile-o').length, 'it has the icon'); } }); @@ -24,7 +24,7 @@ widgetTest('icon and text button', { test(assert) { assert.ok(this.$('button.btn.btn-icon-text').length, 'it has all the classes'); - assert.ok(this.$('button .d-icon.d-icon-plus').length, 'it has the icon'); + assert.ok(this.$('button .d-icon.d-plus').length, 'it has the icon'); assert.ok(this.$('button span.d-button-label').length, 'it has the label'); } }); diff --git a/test/javascripts/widgets/home-logo-test.js.es6 b/test/javascripts/widgets/home-logo-test.js.es6 index 96bd889f50f..80bec5f4bef 100644 --- a/test/javascripts/widgets/home-logo-test.js.es6 +++ b/test/javascripts/widgets/home-logo-test.js.es6 @@ -66,7 +66,7 @@ widgetTest('no logo - minimized', { }, test(assert) { - assert.ok(this.$('.d-icon-home').length === 1); + assert.ok(this.$('.d-home').length === 1); } }); diff --git a/test/javascripts/widgets/post-test.js.es6 b/test/javascripts/widgets/post-test.js.es6 index 0296c9dcf3d..89d72fdbcd8 100644 --- a/test/javascripts/widgets/post-test.js.es6 +++ b/test/javascripts/widgets/post-test.js.es6 @@ -436,7 +436,7 @@ widgetTest("reply directly above", { click('a.reply-to-tab'); andThen(() => { assert.equal(this.$('section.embedded-posts.top .cooked').length, 1); - assert.equal(this.$('section.embedded-posts .d-icon-arrow-up').length, 1); + assert.equal(this.$('section.embedded-posts .d-arrow-up').length, 1); }); } }); @@ -673,7 +673,7 @@ widgetTest("replies - one below, not suppressed", { click('button.show-replies'); andThen(() => { assert.equal(this.$('section.embedded-posts.bottom .cooked').length, 1); - assert.equal(this.$('section.embedded-posts .d-icon-arrow-down').length, 1); + assert.equal(this.$('section.embedded-posts .d-arrow-down').length, 1); }); } }); @@ -760,7 +760,7 @@ widgetTest("topic map - links", { click('nav.buttons button'); andThen(() => { assert.equal(this.$('.map.map-collapsed').length, 0); - assert.equal(this.$('.topic-map .d-icon-chevron-up').length, 1); + assert.equal(this.$('.topic-map .d-chevron-up').length, 1); assert.equal(this.$('.topic-map-expanded').length, 1); assert.equal(this.$('.topic-map-expanded .topic-link').length, 5, 'it limits the links displayed'); }); diff --git a/test/javascripts/widgets/poster-name-test.js.es6 b/test/javascripts/widgets/poster-name-test.js.es6 index c8ab8391d7a..f324e043254 100644 --- a/test/javascripts/widgets/poster-name-test.js.es6 +++ b/test/javascripts/widgets/poster-name-test.js.es6 @@ -38,7 +38,7 @@ widgetTest('extra classes and glyphs', { assert.ok(this.$('span.staff').length); assert.ok(this.$('span.admin').length); assert.ok(this.$('span.moderator').length); - assert.ok(this.$('.d-icon-shield').length); + assert.ok(this.$('.d-shield').length); assert.ok(this.$('span.new-user').length); assert.ok(this.$('span.fish').length); }