From 3a290ee625f463b89751507657e848fc33d9a905 Mon Sep 17 00:00:00 2001 From: Joffrey JAFFEUX Date: Wed, 24 Jan 2018 11:48:20 +0100 Subject: [PATCH] FEATURE: replaces category/tag dropdowns by select-kit --- .../discourse/components/category-drop.js.es6 | 152 ------------------ .../discourse/components/tag-drop.js.es6 | 139 ---------------- .../templates/components/bread-crumbs.hbs | 11 +- .../templates/components/category-drop.hbs | 30 ---- .../templates/components/tag-drop.hbs | 28 ---- .../components/category-drop.js.es6 | 106 ++++++++++++ .../category-drop/category-drop-header.js.es6 | 67 ++++++++ .../select-kit/components/category-row.js.es6 | 15 +- .../select-kit/components/select-kit.js.es6 | 4 +- .../components/single-select.js.es6 | 18 ++- .../select-kit/components/tag-drop.js.es6 | 112 +++++++++++++ .../tag-drop/tag-drop-header.js.es6 | 6 + .../components/tag-drop/tag-drop-row.js.es6 | 8 + .../category-drop/category-drop-header.hbs | 5 + .../templates/components/category-row.hbs | 2 +- .../components/tag-drop/tag-drop-header.hbs | 5 + .../components/tag-drop/tag-drop-row.hbs | 1 + .../stylesheets/common/base/_topic-list.scss | 28 ---- .../stylesheets/common/components/badges.scss | 90 +---------- .../common/select-kit/category-chooser.scss | 3 +- .../common/select-kit/category-drop.scss | 149 +++++++++++++++++ .../common/select-kit/category-row.scss | 4 + .../common/select-kit/select-kit.scss | 4 + .../common/select-kit/tag-drop.scss | 66 ++++++++ .../stylesheets/desktop/topic-list.scss | 7 +- app/assets/stylesheets/mobile.scss | 2 + .../mobile/select-kit/category-drop.scss | 17 ++ .../mobile/select-kit/tag-drop.scss | 17 ++ app/assets/stylesheets/mobile/topic-list.scss | 14 -- 29 files changed, 610 insertions(+), 500 deletions(-) delete mode 100644 app/assets/javascripts/discourse/components/category-drop.js.es6 delete mode 100644 app/assets/javascripts/discourse/components/tag-drop.js.es6 delete mode 100644 app/assets/javascripts/discourse/templates/components/category-drop.hbs delete mode 100644 app/assets/javascripts/discourse/templates/components/tag-drop.hbs create mode 100644 app/assets/javascripts/select-kit/components/category-drop.js.es6 create mode 100644 app/assets/javascripts/select-kit/components/category-drop/category-drop-header.js.es6 create mode 100644 app/assets/javascripts/select-kit/components/tag-drop.js.es6 create mode 100644 app/assets/javascripts/select-kit/components/tag-drop/tag-drop-header.js.es6 create mode 100644 app/assets/javascripts/select-kit/components/tag-drop/tag-drop-row.js.es6 create mode 100644 app/assets/javascripts/select-kit/templates/components/category-drop/category-drop-header.hbs create mode 100644 app/assets/javascripts/select-kit/templates/components/tag-drop/tag-drop-header.hbs create mode 100644 app/assets/javascripts/select-kit/templates/components/tag-drop/tag-drop-row.hbs create mode 100644 app/assets/stylesheets/common/select-kit/category-drop.scss create mode 100644 app/assets/stylesheets/common/select-kit/tag-drop.scss create mode 100644 app/assets/stylesheets/mobile/select-kit/category-drop.scss create mode 100644 app/assets/stylesheets/mobile/select-kit/tag-drop.scss diff --git a/app/assets/javascripts/discourse/components/category-drop.js.es6 b/app/assets/javascripts/discourse/components/category-drop.js.es6 deleted file mode 100644 index 379e326ac84..00000000000 --- a/app/assets/javascripts/discourse/components/category-drop.js.es6 +++ /dev/null @@ -1,152 +0,0 @@ -import { setting } from 'discourse/lib/computed'; -import computed from 'ember-addons/ember-computed-decorators'; - -var get = Ember.get; - -export default Ember.Component.extend({ - classNameBindings: ['category::no-category', 'categories:has-drop', 'categoryStyle'], - categoryStyle: setting('category_style'), - expanded: false, - - tagName: 'li', - - @computed('expanded') - expandIcon(expanded) { - return expanded ? 'd-drop-expanded' : 'd-drop-collapsed'; - }, - - allCategoriesUrl: function() { - if (this.get('subCategory')) { - return this.get('parentCategory.url') || "/"; - } else { - return "/"; - } - }.property('parentCategory.url', 'subCategory'), - - noCategoriesUrl: function() { - return this.get('parentCategory.url') + "/none"; - }.property('parentCategory.url'), - - allCategoriesLabel: function() { - if (this.get('subCategory')) { - return I18n.t('categories.all_subcategories', {categoryName: this.get('parentCategory.name')}); - } - return I18n.t('categories.all'); - }.property('category'), - - dropdownButtonClass: function() { - let result = 'dropdown-header category-dropdown-button'; - if (Em.isNone(this.get('category'))) { - result += ' home'; - } - return result; - }.property('category'), - - categoryColor: function() { - var category = this.get('category'); - - if (category) { - var color = get(category, 'color'); - - if (color) { - var style = ""; - if (color) { style += "background-color: #" + color + ";"; } - return style.htmlSafe(); - } - } - - return "background-color: #eee;".htmlSafe(); - }.property('category'), - - badgeStyle: function() { - let category = this.get('category'); - - const categoryStyle = this.siteSettings.category_style; - if (categoryStyle === 'bullet') { - return; - } - - if (category) { - let color = get(category, 'color'); - let textColor = get(category, 'text_color'); - - if (color || textColor) { - let style = ""; - if (color) { - if (categoryStyle === "bar") { - style += `border-color: #${color};`; - } else if (categoryStyle === "box") { - style += `background-color: #${color};`; - if (textColor) { style += "color: #" + textColor + "; "; } - } - } - - return style.htmlSafe(); - } - } - - if (categoryStyle === 'box') { - return "background-color: #eee; color: #333".htmlSafe(); - } - }.property('category'), - - clickEventName: function() { - return "click.category-drop-" + (this.get('category.id') || "all"); - }.property('category.id'), - - actions: { - expand: function() { - var self = this; - - if(!this.get('renderCategories')){ - this.set('renderCategories',true); - Em.run.next(function(){ - self.send('expand'); - }); - return; - } - - if (this.get('expanded')) { - this.close(); - return; - } - - if (this.get('categories')) { - this.set('expanded', true); - } - var $dropdown = this.$()[0]; - - this.$('a[data-drop-close]').on('click.category-drop', function() { - self.close(); - }); - - Em.run.next(function(){ - self.$('.cat a').add('html').on(self.get('clickEventName'), function(e) { - var $target = $(e.target), - closest = $target.closest($dropdown); - - if ($(e.currentTarget).hasClass('badge-wrapper')){ - self.close(); - } - - return ($(e.currentTarget).hasClass('badge-category') || (closest.length && closest[0] === $dropdown)) ? true : self.close(); - }); - }); - } - }, - - removeEvents: function(){ - $('html').off(this.get('clickEventName')); - this.$('a[data-drop-close]').off('click.category-drop'); - }, - - close: function() { - this.removeEvents(); - this.set('expanded', false); - }, - - willDestroyElement: function() { - this.removeEvents(); - } - -}); diff --git a/app/assets/javascripts/discourse/components/tag-drop.js.es6 b/app/assets/javascripts/discourse/components/tag-drop.js.es6 deleted file mode 100644 index 201d9a134d5..00000000000 --- a/app/assets/javascripts/discourse/components/tag-drop.js.es6 +++ /dev/null @@ -1,139 +0,0 @@ -import { setting } from 'discourse/lib/computed'; -import computed from 'ember-addons/ember-computed-decorators'; - -export default Ember.Component.extend({ - classNameBindings: [':tag-drop', 'tag::no-category', 'tags:has-drop','categoryStyle','tagClass'], - categoryStyle: setting('category_style'), // match the category-drop style - currentCategory: Em.computed.or('secondCategory', 'firstCategory'), - showFilterByTag: setting('show_filter_by_tag'), - showTagDropdown: Em.computed.and('showFilterByTag', 'tags'), - tagId: null, - - tagName: 'li', - - @computed('site.top_tags') - tags(topTags) { - if (this.siteSettings.tags_sort_alphabetically && topTags) { - return topTags.sort(); - } else { - return topTags; - } - }, - - @computed('expanded') - expandedIcon(expanded) { - return expanded ? 'd-drop-expanded' : 'd-drop-collapsed'; - }, - - @computed('tagId') - tagClass() { - if (this.get('tagId')) { - return "tag-" + this.get('tagId'); - } else { - return "tag_all"; - } - }, - - @computed('firstCategory', 'secondCategory') - allTagsUrl() { - if (this.get('currentCategory')) { - return this.get('currentCategory.url') + "?allTags=1"; - } else { - return "/"; - } - }, - - @computed('tag') - allTagsLabel() { - return I18n.t("tagging.selector_all_tags"); - }, - - @computed('tagId') - noTagsSelected() { - return this.get('tagId') === 'none'; - }, - - @computed('firstCategory', 'secondCategory') - noTagsUrl() { - var url = '/tags'; - if (this.get('currentCategory')) { - url += this.get('currentCategory.url'); - } - return url + '/none'; - }, - - @computed('tag') - noTagsLabel() { - return I18n.t("tagging.selector_no_tags"); - }, - - @computed('tag') - dropdownButtonClass() { - let result = 'dropdown-header category-dropdown-button'; - if (Em.isNone(this.get('tag'))) { - result += ' home'; - } - return result; - }, - - @computed('tag') - clickEventName() { - return "click.tag-drop-" + (this.get('tag') || "all"); - }, - - actions: { - expand: function() { - var self = this; - - if(!this.get('renderTags')){ - this.set('renderTags',true); - Em.run.next(function(){ - self.send('expand'); - }); - return; - } - - if (this.get('expanded')) { - this.close(); - return; - } - - if (this.get('tags')) { - this.set('expanded', true); - } - var $dropdown = this.$()[0]; - - this.$('a[data-drop-close]').on('click.tag-drop', function() { - self.close(); - }); - - Em.run.next(function(){ - self.$('.cat a').add('html').on(self.get('clickEventName'), function(e) { - var $target = $(e.target), - closest = $target.closest($dropdown); - - if ($(e.currentTarget).hasClass('badge-wrapper')){ - self.close(); - } - - return ($(e.currentTarget).hasClass('badge-category') || (closest.length && closest[0] === $dropdown)) ? true : self.close(); - }); - }); - } - }, - - removeEvents: function(){ - $('html').off(this.get('clickEventName')); - this.$('a[data-drop-close]').off('click.tag-drop'); - }, - - close: function() { - this.removeEvents(); - this.set('expanded', false); - }, - - willDestroyElement: function() { - this.removeEvents(); - } - -}); diff --git a/app/assets/javascripts/discourse/templates/components/bread-crumbs.hbs b/app/assets/javascripts/discourse/templates/components/bread-crumbs.hbs index bbf8ef4caba..ce6613330e1 100644 --- a/app/assets/javascripts/discourse/templates/components/bread-crumbs.hbs +++ b/app/assets/javascripts/discourse/templates/components/bread-crumbs.hbs @@ -1,7 +1,14 @@ -{{category-drop category=firstCategory categories=parentCategories}} +{{category-drop + category=firstCategory + categories=parentCategories}} {{#if childCategories}} - {{category-drop category=secondCategory parentCategory=firstCategory categories=childCategories subCategory="true" noSubcategories=noSubcategories}} + {{category-drop + category=secondCategory + parentCategory=firstCategory + categories=childCategories + subCategory="true" + noSubcategories=noSubcategories}} {{/if}} {{#if siteSettings.tagging_enabled}} diff --git a/app/assets/javascripts/discourse/templates/components/category-drop.hbs b/app/assets/javascripts/discourse/templates/components/category-drop.hbs deleted file mode 100644 index ba5062a429b..00000000000 --- a/app/assets/javascripts/discourse/templates/components/category-drop.hbs +++ /dev/null @@ -1,30 +0,0 @@ -{{#if category}} - - - {{#if category.read_restricted}} - {{d-icon "lock"}} - {{/if}} - {{category.name}} - -{{else}} - {{#if noSubcategories}} - {{i18n 'categories.no_subcategory'}} - {{else}} - {{allCategoriesLabel}} - {{/if}} -{{/if}} - -{{#if categories}} - - {{d-icon expandIcon}} - -
- - {{#if subCategory}} - - {{/if}} - {{#if renderCategories}} - {{#each categories as |c|}}
{{category-link c allowUncategorized=true hideParent=subCategory}}
{{/each}} - {{/if}} -
-{{/if}} diff --git a/app/assets/javascripts/discourse/templates/components/tag-drop.hbs b/app/assets/javascripts/discourse/templates/components/tag-drop.hbs deleted file mode 100644 index 8dc8869f6f0..00000000000 --- a/app/assets/javascripts/discourse/templates/components/tag-drop.hbs +++ /dev/null @@ -1,28 +0,0 @@ -{{#if showTagDropdown}} - {{#if tagId}} - {{#if noTagsSelected}} - {{noTagsLabel}} - {{else}} - {{tagId}} - {{/if}} - {{else}} - {{allTagsLabel}} - {{/if}} - - {{#if tags}} - - {{d-icon expandedIcon}} - -
- - - {{#if renderTags}} - {{#each tags as |t|}} -
- {{tag-drop-link tagId=t category=currentCategory}} -
- {{/each}} - {{/if}} -
- {{/if}} -{{/if}} diff --git a/app/assets/javascripts/select-kit/components/category-drop.js.es6 b/app/assets/javascripts/select-kit/components/category-drop.js.es6 new file mode 100644 index 00000000000..c589dc2091c --- /dev/null +++ b/app/assets/javascripts/select-kit/components/category-drop.js.es6 @@ -0,0 +1,106 @@ +import ComboBoxComponent from "select-kit/components/combo-box"; +import DiscourseURL from "discourse/lib/url"; +import { default as computed } from "ember-addons/ember-computed-decorators"; +import Category from "discourse/models/category"; +import { categoryBadgeHTML } from "discourse/helpers/category-link"; + +export default ComboBoxComponent.extend({ + pluginApiIdentifiers: ["category-drop"], + classNameBindings: ["categoryStyle"], + classNames: "category-drop", + verticalOffset: 3, + collectionHeight: "200", + content: Ember.computed.alias("categories"), + rowComponent: "category-row", + headerComponent: "category-drop/category-drop-header", + allowAutoSelectFirst: false, + tagName: "li", + categoryStyle: Ember.computed.alias("siteSettings.category_style"), + noCategoriesLabel: I18n.t("categories.no_subcategory"), + mutateAttributes() {}, + + init() { + this._super(); + + if (this.get("category")) { + this.set("value", this.get("category.id")); + } else { + this.set("value", null); + } + if (!this.get("categories")) this.set("categories", []); + + this.get("rowComponentOptions").setProperties({ + hideParentCategory: this.get("subCategory"), + allowUncategorized: true, + displayCategoryDescription: true + }); + }, + + @computed("allCategoriesUrl", "allCategoriesLabel", "noCategoriesUrl", "noCategoriesLabel") + collectionHeader(allCategoriesUrl, allCategoriesLabel, noCategoriesUrl, noCategoriesLabel) { + let shortcuts = ""; + + shortcuts += ` + + ${allCategoriesLabel} + + `; + + if (this.get("subCategory")) { + shortcuts += ` + + ${noCategoriesLabel} + + `; + } + + return shortcuts.htmlSafe(); + }, + + computeHeaderContent() { + let content = this.baseHeaderComputedContent(); + + if (this.get("hasSelection")) { + const category = Category.findById(content.value); + content.label = categoryBadgeHTML(category, { + link: false, + allowUncategorized: true, + hideParent: true + }).htmlSafe(); + } else { + if (this.get("noSubcategories")) { + content.label = this.get("noCategoriesLabel"); + } else { + content.label = this.get("allCategoriesLabel"); + } + } + + return content; + }, + + @computed("parentCategory.name", "subCategory") + allCategoriesLabel(categoryName, subCategory) { + if (subCategory) { + return I18n.t("categories.all_subcategories", { categoryName }); + } + return I18n.t("categories.all"); + }, + + @computed("parentCategory.url", "subCategory") + allCategoriesUrl(parentCategoryUrl, subCategory) { + return subCategory ? ( parentCategoryUrl || "/" ) : "/"; + }, + + @computed("parentCategory.url") + noCategoriesUrl(parentCategoryUrl) { + return `${parentCategoryUrl}/none`; + }, + + actions: { + onSelect(categoryId) { + const category = Category.findById(parseInt(categoryId, 10)); + const categoryURL = Discourse.getURL("/c/") + Discourse.Category.slugFor(category); + DiscourseURL.routeTo(categoryURL); + } + } +}); diff --git a/app/assets/javascripts/select-kit/components/category-drop/category-drop-header.js.es6 b/app/assets/javascripts/select-kit/components/category-drop/category-drop-header.js.es6 new file mode 100644 index 00000000000..84dec7d4d9e --- /dev/null +++ b/app/assets/javascripts/select-kit/components/category-drop/category-drop-header.js.es6 @@ -0,0 +1,67 @@ +import ComboBoxSelectBoxHeaderComponent from "select-kit/components/combo-box/combo-box-header"; +import computed from "ember-addons/ember-computed-decorators"; +import Category from "discourse/models/category"; + +export default ComboBoxSelectBoxHeaderComponent.extend({ + layoutName: "select-kit/templates/components/category-drop/category-drop-header", + classNames: "category-drop-header", + + classNameBindings: ['categoryStyleClass'], + categoryStyleClass: Ember.computed.alias('site.category_style'), + + @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.color") + categoryBackgroundColor(categoryColor) { + return categoryColor || "#e9e9e9"; + }, + + @computed("category.text_color") + categoryTextColor(categoryTextColor) { + return categoryTextColor || "#333"; + }, + + @computed("category", "categoryBackgroundColor", "categoryTextColor") + categoryStyle(category, categoryBackgroundColor, categoryTextColor) { + const categoryStyle = this.siteSettings.category_style; + + if (categoryStyle === "bullet") return; + + if (category) { + if (categoryBackgroundColor || categoryTextColor) { + let style = ""; + if (categoryBackgroundColor) { + if (categoryStyle === "bar") { + style += `border-color: #${categoryBackgroundColor};`; + } else if (categoryStyle === "box") { + style += `background-color: #${categoryBackgroundColor};`; + if (categoryTextColor) { style += `color: #${categoryTextColor};`; } + } + } + + return style.htmlSafe(); + } + } + + if (categoryStyle === "box") { + return `background-color: ${categoryBackgroundColor}; color: ${categoryTextColor}`.htmlSafe(); + } + }, + + didRender() { + this._super(); + + this.$().attr("style", this.get("categoryStyle")); + this.$(".caret-icon").attr("style", this.get("categoryStyle")); + }, +}); diff --git a/app/assets/javascripts/select-kit/components/category-row.js.es6 b/app/assets/javascripts/select-kit/components/category-row.js.es6 index da59a4cfe99..ccd131c75d5 100644 --- a/app/assets/javascripts/select-kit/components/category-row.js.es6 +++ b/app/assets/javascripts/select-kit/components/category-row.js.es6 @@ -7,6 +7,10 @@ export default SelectKitRowComponent.extend({ layoutName: "select-kit/templates/components/category-row", classNames: "category-row", + hideParentCategory: Ember.computed.bool("options.hideParentCategory"), + allowUncategorized: Ember.computed.bool("options.allowUncategorized"), + categoryLink: Ember.computed.bool("options.categoryLink"), + @computed("options.displayCategoryDescription") displayCategoryDescription(displayCategoryDescription) { if (Ember.isNone(displayCategoryDescription)) { @@ -31,9 +35,9 @@ export default SelectKitRowComponent.extend({ @computed("category") badgeForCategory(category) { return categoryBadgeHTML(category, { - link: false, - allowUncategorized: true, - hideParent: true + link: this.get("categoryLink"), + allowUncategorized: this.get("allowUncategorized"), + hideParent: this.get("hideParentCategory") }).htmlSafe(); }, @@ -57,7 +61,10 @@ export default SelectKitRowComponent.extend({ return category.get("parent_category_id"); }, - topicCount: Ember.computed.alias("category.topic_count"), + @computed("category.topic_count") + topicCount(topicCount) { + return `× ${topicCount}`.htmlSafe(); + }, @computed("displayCategoryDescription", "category.description") shouldDisplayDescription(displayCategoryDescription, description) { diff --git a/app/assets/javascripts/select-kit/components/select-kit.js.es6 b/app/assets/javascripts/select-kit/components/select-kit.js.es6 index 63f597341c8..d5e2be02473 100644 --- a/app/assets/javascripts/select-kit/components/select-kit.js.es6 +++ b/app/assets/javascripts/select-kit/components/select-kit.js.es6 @@ -22,7 +22,8 @@ export default Ember.Component.extend(UtilsMixin, PluginApiMixin, DomHelpersMixi "isAbove", "isBelow", "isLeftAligned", - "isRightAligned" + "isRightAligned", + "hasSelection", ], isDisabled: false, isExpanded: false, @@ -64,6 +65,7 @@ export default Ember.Component.extend(UtilsMixin, PluginApiMixin, DomHelpersMixi nameChanges: false, allowContentReplacement: false, collectionHeader: null, + allowAutoSelectFirst: true, init() { this._super(); diff --git a/app/assets/javascripts/select-kit/components/single-select.js.es6 b/app/assets/javascripts/select-kit/components/single-select.js.es6 index 2dfe76904a2..495757dd286 100644 --- a/app/assets/javascripts/select-kit/components/single-select.js.es6 +++ b/app/assets/javascripts/select-kit/components/single-select.js.es6 @@ -1,6 +1,5 @@ import SelectKitComponent from "select-kit/components/select-kit"; -import { on } from "ember-addons/ember-computed-decorators"; -import computed from "ember-addons/ember-computed-decorators"; +import { default as computed, on } from 'ember-addons/ember-computed-decorators'; const { get, isNone, isEmpty, isPresent, run } = Ember; export default SelectKitComponent.extend({ @@ -46,8 +45,11 @@ export default SelectKitComponent.extend({ }, _beforeWillComputeValue(value) { - if (!isEmpty(this.get("content")) && isEmpty(value) && isNone(this.get("none"))) { - value = this.valueForContentItem(get(this.get("content"), "firstObject")); + if (!isEmpty(this.get("content")) && + isEmpty(value) && + isNone(this.get("none")) && + this.get("allowAutoSelectFirst")) { + value = this.valueForContentItem(get(this.get("content"), "firstObject")); } switch (typeof value) { @@ -84,7 +86,7 @@ export default SelectKitComponent.extend({ @computed("computedContent.[]", "computedValue", "filter", "shouldFilter") filteredComputedContent(computedContent, computedValue, filter, shouldFilter) { - if (shouldFilter === true) { + if (shouldFilter) { computedContent = this.filterComputedContent(computedContent, computedValue, filter); } @@ -113,7 +115,7 @@ export default SelectKitComponent.extend({ autoHighlight() { run.schedule("afterRender", () => { - if (!isNone(this.get("highlightedValue"))) { return; } + if (!isNone(this.get("highlightedValue"))) return; const filteredComputedContent = this.get("filteredComputedContent"); const displayCreateRow = this.get("shouldDisplayCreateRow"); @@ -129,13 +131,13 @@ export default SelectKitComponent.extend({ return; } - if (displayCreateRow === true && isEmpty(filteredComputedContent)) { + if (displayCreateRow && isEmpty(filteredComputedContent)) { this.send("highlight", this.get("createRowComputedContent")); } else if (!isEmpty(filteredComputedContent)) { this.send("highlight", get(filteredComputedContent, "firstObject")); } - else if (isEmpty(filteredComputedContent) && isPresent(none) && displayCreateRow === false) { + else if (isEmpty(filteredComputedContent) && isPresent(none) && !displayCreateRow) { this.send("highlight", none); } }); diff --git a/app/assets/javascripts/select-kit/components/tag-drop.js.es6 b/app/assets/javascripts/select-kit/components/tag-drop.js.es6 new file mode 100644 index 00000000000..8919679f757 --- /dev/null +++ b/app/assets/javascripts/select-kit/components/tag-drop.js.es6 @@ -0,0 +1,112 @@ +import ComboBoxComponent from "select-kit/components/combo-box"; +import DiscourseURL from "discourse/lib/url"; +import { default as computed } from "ember-addons/ember-computed-decorators"; +const { isEmpty } = Ember; + +export default ComboBoxComponent.extend({ + pluginApiIdentifiers: ["tag-drop"], + classNameBindings: ["categoryStyle", "tagClass"], + classNames: "tag-drop", + verticalOffset: 3, + collectionHeight: "200", + value: Ember.computed.alias("tagId"), + headerComponent: "tag-drop/tag-drop-header", + rowComponent: "tag-drop/tag-drop-row", + allowAutoSelectFirst: false, + tagName: "li", + showFilterByTag: Ember.computed.alias("siteSettings.show_filter_by_tag"), + currentCategory: Ember.computed.or("secondCategory", "firstCategory"), + tagId: null, + categoryStyle: Ember.computed.alias("siteSettings.category_style"), + mutateAttributes() {}, + + @computed("tagId") + noTagsSelected() { + return this.get("tagId") === "none"; + }, + + @computed("showFilterByTag", "content") + isHidden(showFilterByTag, content) { + if (showFilterByTag && !isEmpty(content)) return false; + return true; + }, + + computeHeaderContent() { + let content = this.baseHeaderComputedContent(); + + if (!content.value) { + if (this.get("noTagsSelected")) { + content.label = this.get("noTagsLabel"); + } else { + content.label = this.get("allTagsLabel"); + } + } + + return content; + }, + + @computed("tagId") + tagClass(tagId) { + return tagId ? `tag-${tagId}` : "tag_all"; + }, + + @computed("firstCategory", "secondCategory") + allTagsUrl() { + if (this.get("currentCategory")) { + return this.get("currentCategory.url") + "?allTags=1"; + } else { + return "/"; + } + }, + + @computed("firstCategory", "secondCategory") + noTagsUrl() { + var url = "/tags"; + if (this.get("currentCategory")) { + url += this.get("currentCategory.url"); + } + return `${url}/none`; + }, + + @computed("allTagsUrl", "allTagsLabel", "noTagsUrl", "noTagsLabel") + collectionHeader(allTagsUrl, allTagsLabel, noTagsUrl, noTagsLabel) { + return ` + + ${allTagsLabel} + + + ${noTagsLabel} + + `; + }, + + @computed("tag") + allTagsLabel() { + return I18n.t("tagging.selector_all_tags"); + }, + + @computed("tag") + noTagsLabel() { + return I18n.t("tagging.selector_no_tags"); + }, + + @computed("site.top_tags") + content(topTags) { + if (this.siteSettings.tags_sort_alphabetically && topTags) { + return topTags.sort(); + } else { + return topTags; + } + }, + + actions: { + onSelect(tagId) { + let url = "/tags"; + if (this.get("currentCategory")) { + url += this.get("currentCategory.url"); + } + url = `${url}/${tagId}`; + DiscourseURL.routeTo(url); + } + } +}); diff --git a/app/assets/javascripts/select-kit/components/tag-drop/tag-drop-header.js.es6 b/app/assets/javascripts/select-kit/components/tag-drop/tag-drop-header.js.es6 new file mode 100644 index 00000000000..4b243f4580c --- /dev/null +++ b/app/assets/javascripts/select-kit/components/tag-drop/tag-drop-header.js.es6 @@ -0,0 +1,6 @@ +import ComboBoxSelectBoxHeaderComponent from "select-kit/components/combo-box/combo-box-header"; + +export default ComboBoxSelectBoxHeaderComponent.extend({ + layoutName: "select-kit/templates/components/tag-drop/tag-drop-header", + classNames: "tag-drop-header", +}); diff --git a/app/assets/javascripts/select-kit/components/tag-drop/tag-drop-row.js.es6 b/app/assets/javascripts/select-kit/components/tag-drop/tag-drop-row.js.es6 new file mode 100644 index 00000000000..cb87469d919 --- /dev/null +++ b/app/assets/javascripts/select-kit/components/tag-drop/tag-drop-row.js.es6 @@ -0,0 +1,8 @@ +import SelectKitRowComponent from "select-kit/components/select-kit/select-kit-row"; + +export default SelectKitRowComponent.extend({ + layoutName: "select-kit/templates/components/tag-drop/tag-drop-row", + classNames: "tag-drop-row", + + tagId: Ember.computed.alias("computedContent.value") +}); diff --git a/app/assets/javascripts/select-kit/templates/components/category-drop/category-drop-header.hbs b/app/assets/javascripts/select-kit/templates/components/category-drop/category-drop-header.hbs new file mode 100644 index 00000000000..7928a3b94b9 --- /dev/null +++ b/app/assets/javascripts/select-kit/templates/components/category-drop/category-drop-header.hbs @@ -0,0 +1,5 @@ + + {{{label}}} + + +{{d-icon caretIcon class="caret-icon"}} diff --git a/app/assets/javascripts/select-kit/templates/components/category-row.hbs b/app/assets/javascripts/select-kit/templates/components/category-row.hbs index 5d0908be623..980a43c306b 100644 --- a/app/assets/javascripts/select-kit/templates/components/category-row.hbs +++ b/app/assets/javascripts/select-kit/templates/components/category-row.hbs @@ -7,7 +7,7 @@ {{else}}
{{badgeForCategory}} - × {{topicCount}} + {{topicCount}}
{{/if}} diff --git a/app/assets/javascripts/select-kit/templates/components/tag-drop/tag-drop-header.hbs b/app/assets/javascripts/select-kit/templates/components/tag-drop/tag-drop-header.hbs new file mode 100644 index 00000000000..7928a3b94b9 --- /dev/null +++ b/app/assets/javascripts/select-kit/templates/components/tag-drop/tag-drop-header.hbs @@ -0,0 +1,5 @@ + + {{{label}}} + + +{{d-icon caretIcon class="caret-icon"}} diff --git a/app/assets/javascripts/select-kit/templates/components/tag-drop/tag-drop-row.hbs b/app/assets/javascripts/select-kit/templates/components/tag-drop/tag-drop-row.hbs new file mode 100644 index 00000000000..e8adb89fe43 --- /dev/null +++ b/app/assets/javascripts/select-kit/templates/components/tag-drop/tag-drop-row.hbs @@ -0,0 +1 @@ +{{tagId}} diff --git a/app/assets/stylesheets/common/base/_topic-list.scss b/app/assets/stylesheets/common/base/_topic-list.scss index 154db643381..1dda299da24 100644 --- a/app/assets/stylesheets/common/base/_topic-list.scss +++ b/app/assets/stylesheets/common/base/_topic-list.scss @@ -199,11 +199,6 @@ } .list-controls { - .category-dropdown-menu .home { - color: $primary; - margin-left: 8px; - } - clear: both; } @@ -253,29 +248,6 @@ ol.category-breadcrumb { } } -.list-controls .category-dropdown-menu { - overflow-x: hidden; - overflow-y: auto; - position: absolute; - border: 1px solid $primary-low; - background-color: $secondary; - z-index: z("dropdown"); - - a.badge-category, a.badge-category-parent { - line-height: $line-height-large; - overflow:hidden; - margin-bottom: 0; - } - a.badge-category, .dropdown-header { - font-size: $font-down-1; - font-weight: bold; - float: none; - text-transform: none; - max-width:200px; - text-overflow:ellipsis; - } -} - .d-icon-thumb-tack.unpinned { @include fa-icon-rotate(180deg, 1); color: $primary; diff --git a/app/assets/stylesheets/common/components/badges.scss b/app/assets/stylesheets/common/components/badges.scss index c33be86a7b1..9e8daf62fbd 100644 --- a/app/assets/stylesheets/common/components/badges.scss +++ b/app/assets/stylesheets/common/components/badges.scss @@ -68,9 +68,9 @@ margin-right: 12px; .extra-info-wrapper & { - margin-top: .25em; + margin-top: .25em; } - + span.badge-category { color: $primary; overflow: hidden; @@ -158,103 +158,21 @@ .list-controls { .category-breadcrumb { - a.badge-category, .dropdown-header { + a.badge-category { display: inline-block; padding: 6px 8px; line-height: $line-height-medium; - - &.category-dropdown-button { - margin-left: -.3em; - padding: 6px; - width: 13px; - - .d-icon-caret-right { - margin-left: 2px; - } - } - } - - li.bar>.dropdown-header:not(.home):first-child { - border-left: 5px solid; - font-size: $font-0; - } - - li.bar>.dropdown-header { - background: $primary-low; - color: $primary; - } - - li.bullet>.dropdown-header { - background: $primary-low; - color: $primary; - - .badge-category-bg { - width: 10px; - height: 10px; - display: inline-block; - margin: 0 2px; - } } } - - .category-dropdown-menu { - .dropdown-header { - &.home { - margin-left: 4px; - padding-left: 0; - } - } - .cat { - line-height: $line-height-large; - } - .badge-wrapper { - box-sizing: border-box; - - &.bar { - padding: 5px 0; - width: 100%; - .badge-category { - max-width: 100px; - } - } - &.none { - padding: 5px; - } - &.bullet { - padding: 5px; - width: 100%; - .badge-category { - max-width: 100px; - } - } - &.box { - margin-top: 0; - width: 100%; - line-height: $line-height-small; - vertical-align: text-top; - padding: 0; - span.badge-category { - max-width: 100px; - padding: 5px; - } - } - - } - - } - } - - - // Notification badge // -------------------------------------------------- .badge-notification { @extend %badge; padding: 3px 5px; - min-width: 8px; + min-width: 8px; vertical-align: middle; color: $secondary; font-size: $font-down-2; diff --git a/app/assets/stylesheets/common/select-kit/category-chooser.scss b/app/assets/stylesheets/common/select-kit/category-chooser.scss index 2dd1dc82ca1..503a9bd275c 100644 --- a/app/assets/stylesheets/common/select-kit/category-chooser.scss +++ b/app/assets/stylesheets/common/select-kit/category-chooser.scss @@ -23,11 +23,12 @@ .topic-count { font-size: $font-down-2; color: $primary; + white-space: nowrap; } .category-status { color: $primary; - line-height: $line-height-large; + line-height: $line-height-large; -webkit-box-flex: 0; -ms-flex: 1 1 auto; flex: 1 1 auto; diff --git a/app/assets/stylesheets/common/select-kit/category-drop.scss b/app/assets/stylesheets/common/select-kit/category-drop.scss new file mode 100644 index 00000000000..98448729b2b --- /dev/null +++ b/app/assets/stylesheets/common/select-kit/category-drop.scss @@ -0,0 +1,149 @@ +.select-kit { + &.combo-box { + &.category-drop { + min-width: auto; + + .badge-wrapper { + font-size: $font-0; + font-weight: normal; + line-height: $line-height-large; + + &.box { + margin: 0; + + span.badge-category { + margin: 0; + } + } + } + + .category-drop-header { + padding: 6px 10px; + } + + &.bar.has-selection .category-drop-header { + padding: 1.5px 10px; + } + + &.bullet.has-selection .category-drop-header { + padding: 5.25px 10px; + } + + &.box.has-selection .category-drop-header { + padding: 4.5px 10px; + } + + &.none.has-selection .category-drop-header { + padding: 4.5px 10px; + } + + .category-drop-header { + background: $primary-low; + color: $primary; + border: none; + padding: 6px 10px; + font-size: $font-up-1; + line-height: $line-height-medium; + transition: none; + + .badge-category { + display: flex; + align-items: center; + } + + .badge-wrapper { + margin-right: 0; + } + + .fa { + font-size: $font-up-1; + } + + .caret-icon { + opacity: 1; + } + } + + .select-kit-collection { + display: flex; + flex-direction: column; + padding: 0; + min-width: 100px; + + .collection-header { + .category-filter { + white-space: nowrap; + color: $primary; + font-size: $font-down-1; + line-height: $line-height-medium; + font-weight: bold; + display: block; + padding: 10px 5px; + + &:hover { + text-decoration: underline; + } + } + } + } + + .select-kit-body { + width: auto; + min-width: 300px; + border-radius: 0; + -webkit-box-shadow: 0 2px 2px rgba(0,0,0,0.4); + box-shadow: 0 2px 2px rgba(0,0,0,0.4); + } + + .select-kit-row { + margin: 0; + font-size: $font-down-1; + font-weight: bold; + flex-direction: column; + align-items: flex-start; + padding: 5px; + + .category-desc { + font-weight: normal; + margin-top: 3px; + color: $primary-medium; + } + + .category-status { + align-items: center; + } + + &.no-content { + font-weight: normal; + } + + &:not(.no-content) { + padding: 5px; + } + + .topic-count { + margin-left: 5px; + font-weight: normal; + } + + .badge-wrapper { + margin: 0; + display: flex; + flex: 1; + } + } + + .select-kit-row .badge-wrapper.box { + padding: 2.5px 0; + } + + .select-kit-row .badge-wrapper.bullet, .select-kit-row .badge-wrapper.none { + margin: 2.5px; + } + + .select-kit-wrapper { + display: none; + } + } + } +} diff --git a/app/assets/stylesheets/common/select-kit/category-row.scss b/app/assets/stylesheets/common/select-kit/category-row.scss index b572f3a1822..b8ad1d8f503 100644 --- a/app/assets/stylesheets/common/select-kit/category-row.scss +++ b/app/assets/stylesheets/common/select-kit/category-row.scss @@ -13,5 +13,9 @@ margin-top: 1px; } } + + .topic-count { + white-space: nowrap; + } } } diff --git a/app/assets/stylesheets/common/select-kit/select-kit.scss b/app/assets/stylesheets/common/select-kit/select-kit.scss index 72f67b1f0d2..1cd2bcb3b0a 100644 --- a/app/assets/stylesheets/common/select-kit/select-kit.scss +++ b/app/assets/stylesheets/common/select-kit/select-kit.scss @@ -161,6 +161,10 @@ -ms-flex-pack: start; justify-content: flex-start; + &.no-content { + white-space: nowrap; + } + .name { margin: 0; overflow: hidden; diff --git a/app/assets/stylesheets/common/select-kit/tag-drop.scss b/app/assets/stylesheets/common/select-kit/tag-drop.scss new file mode 100644 index 00000000000..2cab61d0580 --- /dev/null +++ b/app/assets/stylesheets/common/select-kit/tag-drop.scss @@ -0,0 +1,66 @@ +.select-kit { + &.combo-box { + &.tag-drop { + min-width: auto; + + .tag-drop-header { + background: $primary-low; + color: $primary; + border: none; + padding: 4.5px 10px; + font-size: $font-up-1; + line-height: $line-height-large; + + .d-icon { + opacity: 1; + font-size: $font-0; + } + } + + .select-kit-collection { + display: flex; + flex-direction: column; + padding: 0; + + .collection-header { + .tag-filter { + white-space: nowrap; + color: $primary; + font-size: $font-down-1; + line-height: $line-height-medium; + font-weight: bold; + display: block; + padding: 5px; + + &:hover { + text-decoration: underline; + } + } + } + } + + .select-kit-body { + width: auto; + min-width: 100px; + border-radius: 0; + -webkit-box-shadow: 0 2px 2px rgba(0,0,0,0.4); + box-shadow: 0 2px 2px rgba(0,0,0,0.4); + } + + .select-kit-row { + margin: 0; + font-size: $font-down-1; + font-weight: bold; + color: $tertiary; + + &.no-content { + font-weight: normal; + } + } + + .select-kit-wrapper { + display: none; + } + } + } +} diff --git a/app/assets/stylesheets/desktop/topic-list.scss b/app/assets/stylesheets/desktop/topic-list.scss index f287f2097a5..5ed43bbb45e 100644 --- a/app/assets/stylesheets/desktop/topic-list.scss +++ b/app/assets/stylesheets/desktop/topic-list.scss @@ -23,7 +23,7 @@ float: none; } - a.badge-category, .dropdown-header { + a.badge-category { padding: 3px 12px; font-size: $font-up-1; } @@ -257,11 +257,6 @@ } } - .category-dropdown-menu { - max-height: 350px; - min-width: 134px; - } - #bulk-select { position: fixed; right: 20px; diff --git a/app/assets/stylesheets/mobile.scss b/app/assets/stylesheets/mobile.scss index 39242962431..08abaaf2ae8 100644 --- a/app/assets/stylesheets/mobile.scss +++ b/app/assets/stylesheets/mobile.scss @@ -27,6 +27,8 @@ // Import all component-specific files @import "mobile/components/*"; +@import "mobile/select-kit/*"; + /* These files doesn't actually exist, they are injected by Stylesheet::Compiler. */ @import "plugins"; diff --git a/app/assets/stylesheets/mobile/select-kit/category-drop.scss b/app/assets/stylesheets/mobile/select-kit/category-drop.scss new file mode 100644 index 00000000000..6205494dea3 --- /dev/null +++ b/app/assets/stylesheets/mobile/select-kit/category-drop.scss @@ -0,0 +1,17 @@ +.select-kit { + &.combo-box { + &.category-drop { + .category-drop-header { + font-size: $font-0; + + .d-icon { + font-size: $font-0; + } + } + + .select-kit-row { + font-weight: normal; + } + } + } +} diff --git a/app/assets/stylesheets/mobile/select-kit/tag-drop.scss b/app/assets/stylesheets/mobile/select-kit/tag-drop.scss new file mode 100644 index 00000000000..9f2dfbd55f8 --- /dev/null +++ b/app/assets/stylesheets/mobile/select-kit/tag-drop.scss @@ -0,0 +1,17 @@ +.select-kit { + &.combo-box { + &.tag-drop { + .tag-drop-header { + font-size: $font-0; + + .d-icon { + font-size: $font-0; + } + } + + .select-kit-row { + font-weight: normal; + } + } + } +} diff --git a/app/assets/stylesheets/mobile/topic-list.scss b/app/assets/stylesheets/mobile/topic-list.scss index c2808e80a51..8e7022e8e5e 100644 --- a/app/assets/stylesheets/mobile/topic-list.scss +++ b/app/assets/stylesheets/mobile/topic-list.scss @@ -309,12 +309,6 @@ tr.category-topic-link { // Misc. stuff // -------------------------------------------------- -.list-controls { - .category-dropdown-button { - padding: 4px 10px 4px 8px; - } -} - .btn-group .dropdown-toggle:active, .btn-group.open .dropdown-toggle { outline: 0; @@ -387,14 +381,6 @@ ol.category-breadcrumb { margin: 5px 10px 0 0; } -.category-dropdown-menu { - height: 200px; - - a.badge-category { - line-height: $line-height-large; - } -} - .top-lists { h2 { margin-left: 10px; } .topic-list { padding-bottom: 10px; }