FEATURE: replaces tag-chooser/tag-group-chooser with select-kit component

These component were also the last using select2. As a consequence select2 is removed from Discourse in this commit.
This commit is contained in:
Joffrey JAFFEUX 2018-02-26 11:42:57 +01:00 committed by GitHub
parent a9699da672
commit ac701696b3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
53 changed files with 637 additions and 4970 deletions

View File

@ -1,142 +0,0 @@
import renderTag from 'discourse/lib/render-tag';
function formatTag(t) {
return renderTag(t.id, {count: t.count, noHref: true});
}
export default Ember.TextField.extend({
classNameBindings: [':tag-chooser'],
attributeBindings: ['tabIndex', 'placeholderKey', 'categoryId'],
init() {
this._super();
const tags = this.get('tags') || [];
this.set('value', tags.join(", "));
if (this.get('allowCreate') !== false) {
this.set('allowCreate', this.site.get('can_create_tag'));
}
this.set('termMatchesForbidden', false);
},
_valueChanged: function() {
const tags = this.get('value').split(',').map(v => v.trim()).reject(v => v.length === 0).uniq();
this.set('tags', tags);
}.observes('value'),
_tagsChanged: function() {
const $tagChooser = this.$(),
val = this.get('value');
if ($tagChooser && val !== this.get('tags')) {
if (this.get('tags')) {
const data = this.get('tags').map((t) => {return {id: t, text: t};});
$tagChooser.select2('data', data);
} else {
$tagChooser.select2('data', []);
}
}
}.observes('tags'),
didInsertElement() {
this._super();
const self = this;
const filterRegexp = new RegExp(this.site.tags_filter_regexp, "g");
let limit = this.siteSettings.max_tags_per_topic;
if (this.get('unlimitedTagCount')) {
limit = null;
} else if (this.get('limit')) {
limit = parseInt(this.get('limit'));
}
this.$().select2({
tags: true,
placeholder: this.get('placeholder') === "" ? "" : I18n.t(this.get('placeholderKey') || 'tagging.choose_for_topic'),
maximumInputLength: this.siteSettings.max_tag_length,
maximumSelectionSize: limit,
width: this.get('width') || 'resolve',
initSelection(element, callback) {
const data = [];
function splitVal(string, separator) {
var val, i, l;
if (string === null || string.length < 1) return [];
val = string.split(separator);
for (i = 0, l = val.length; i < l; i = i + 1) val[i] = $.trim(val[i]);
return val;
}
$(splitVal(element.val(), ",")).each(function () {
data.push({
id: this,
text: this
});
});
callback(data);
},
createSearchChoice(term, data) {
term = term.replace(filterRegexp, '').trim().toLowerCase();
// No empty terms, make sure the user has permission to create the tag
if (!term.length || !self.get('allowCreate') || self.get('termMatchesForbidden')) return;
if ($(data).filter(function() {
return this.text.localeCompare(term) === 0;
}).length === 0) {
return { id: term, text: term };
}
},
createSearchChoicePosition(list, item) {
// Search term goes on the bottom
list.push(item);
},
formatSelection(data) {
return data ? renderTag(this.text(data), {noHref: true}) : undefined;
},
formatSelectionCssClass() {
return "discourse-tag-select2";
},
formatResult: formatTag,
multiple: true,
ajax: {
quietMillis: 200,
cache: true,
url: Discourse.getURL("/tags/filter/search"),
dataType: 'json',
data: function (term) {
const selectedTags = self.get('tags');
const d = {
q: term,
limit: self.siteSettings.max_tag_search_results,
categoryId: self.get('categoryId')
};
if (selectedTags) {
d.selected_tags = selectedTags.slice(0,100);
}
if (!self.get('everyTag')) {
d.filterForInput = true;
}
return d;
},
results: function (data) {
if (self.siteSettings.tags_sort_alphabetically) {
data.results = data.results.sort(function(a,b) { return a.id > b.id; });
}
self.set('termMatchesForbidden', data.forbidden ? true : false);
return data;
}
},
});
},
willDestroyElement() {
this._super();
this.$().select2('destroy');
}
});

View File

@ -1,86 +0,0 @@
function renderTagGroup(tag) {
return "<a class='discourse-tag'>" + Handlebars.Utils.escapeExpression(tag.text ? tag.text : tag) + "</a>";
};
export default Ember.TextField.extend({
classNameBindings: [':tag-chooser'],
attributeBindings: ['tabIndex', 'placeholderKey', 'categoryId'],
_initValue: function() {
const names = this.get('tagGroups') || [];
this.set('value', names.join(","));
}.on('init'),
_valueChanged: function() {
const names = this.get('value').split(',').map(v => v.trim()).reject(v => v.length === 0).uniq();
if ( this.get('tagGroups').join(',') !== this.get('value') ) {
this.set('tagGroups', names);
}
}.observes('value'),
_tagGroupsChanged: function() {
const $chooser = this.$(),
val = this.get('value');
if ($chooser && val !== this.get('tagGroups')) {
if (this.get('tagGroups')) {
const data = this.get('tagGroups').map((t) => {return {id: t, text: t};});
$chooser.select2('data', data);
} else {
$chooser.select2('data', []);
}
}
}.observes('tagGroups'),
_initializeChooser: function() {
const self = this;
this.$().select2({
tags: true,
placeholder: this.get('placeholderKey') ? I18n.t(this.get('placeholderKey')) : null,
initSelection(element, callback) {
const data = [];
function splitVal(string, separator) {
var val, i, l;
if (string === null || string.length < 1) return [];
val = string.split(separator);
for (i = 0, l = val.length; i < l; i = i + 1) val[i] = $.trim(val[i]);
return val;
}
$(splitVal(element.val(), ",")).each(function () {
data.push({ id: this, text: this });
});
callback(data);
},
formatSelection: function (data) {
return data ? renderTagGroup(this.text(data)) : undefined;
},
formatSelectionCssClass: function(){
return "discourse-tag-select2";
},
formatResult: renderTagGroup,
multiple: true,
ajax: {
quietMillis: 200,
cache: true,
url: Discourse.getURL("/tag_groups/filter/search"),
dataType: 'json',
data: function (term) {
return { q: term, limit: self.siteSettings.max_tag_search_results };
},
results: function (data) {
data.results = data.results.sort(function(a,b) { return a.text > b.text; });
return data;
}
},
});
}.on('didInsertElement'),
_destroyChooser: function() {
this.$().select2('destroy');
}.on('willDestroyElement')
});

View File

@ -1,6 +1,6 @@
import PreferencesTabController from "discourse/mixins/preferences-tab-controller";
import { popupAjaxError } from 'discourse/lib/ajax-error';
import { default as computed } from "ember-addons/ember-computed-decorators";
import computed from "ember-addons/ember-computed-decorators";
export default Ember.Controller.extend(PreferencesTabController, {
saveAttrNames: [
@ -12,7 +12,7 @@ export default Ember.Controller.extend(PreferencesTabController, {
@computed("model.watchedCategories", "model.watchedFirstPostCategories", "model.trackedCategories", "model.mutedCategories")
selectedCategories(watched, watchedFirst, tracked, muted) {
return [].concat(watched, watchedFirst, tracked, muted);
return [].concat(watched, watchedFirst, tracked, muted).filter(t => t);
},
canSave: function() {

View File

@ -1,8 +1,8 @@
import PreferencesTabController from "discourse/mixins/preferences-tab-controller";
import { popupAjaxError } from 'discourse/lib/ajax-error';
import computed from "ember-addons/ember-computed-decorators";
export default Ember.Controller.extend(PreferencesTabController, {
saveAttrNames: [
'muted_tags',
'tracked_tags',
@ -10,6 +10,11 @@ export default Ember.Controller.extend(PreferencesTabController, {
'watching_first_post_tags'
],
@computed("model.watched_tags", "model.watching_first_post_tags", "model.tracked_tags", "model.muted_tags")
selectedTags(watched, watchedFirst, tracked, muted) {
return [].concat(watched, watchedFirst, tracked, muted).filter(t => t);
},
actions: {
save() {
this.set('saved', false);

View File

@ -1,5 +1,5 @@
<p>{{i18n (concat "topics.bulk." title)}}</p>
<p>{{tag-chooser tags=tags categoryId=categoryId}}</p>
<p>{{tag-chooser filterPlaceholder=null tags=tags categoryId=categoryId}}</p>
{{d-button action=action disabled=emptyTags label=(concat "topics.bulk." label)}}

View File

@ -1,7 +1,11 @@
<section class="field">
<p>{{i18n 'category.tags_allowed_tags'}}</p>
{{tag-chooser placeholderKey="category.tags_placeholder" tags=category.allowed_tags everyTag="true" unlimitedTagCount="true"}}
{{tag-chooser
filterPlaceholder="category.tags_placeholder"
tags=category.allowed_tags
everyTag=true
unlimitedTagCount=true}}
<p>{{i18n 'category.tags_allowed_tag_groups'}}</p>
{{tag-group-chooser placeholderKey="category.tag_groups_placeholder" tagGroups=category.allowed_tag_groups}}
{{tag-group-chooser tagGroups=category.allowed_tag_groups}}
</section>

View File

@ -52,7 +52,7 @@
{{/each}}
</div>
{{else if editTags}}
{{tag-chooser tags=buffered.tags categoryId=buffered.category_id width='100%'}}
{{tag-chooser tags=buffered.tags categoryId=buffered.category_id}}
{{/if}}
<div class='queue-controls'>

View File

@ -40,7 +40,12 @@
<div class="control-group">
<label class="control-label" for="search-with-tags">{{i18n "search.advanced.with_tags.label"}}</label>
<div class="controls">
{{tag-chooser tags=searchedTerms.tags blacklist=searchedTerms.tags allowCreate=false placeholder="" everyTag="true" unlimitedTagCount="true" width="70%"}}
{{tag-chooser
tags=searchedTerms.tags
allowCreate=false
filterPlaceholder=null
everyTag=true
unlimitedTagCount=true}}
<section class="field">
<label>{{ input type="checkbox" class="all-tags" checked=searchedTerms.special.all_tags}} {{i18n "search.advanced.filters.all_tags"}} </label>
</section>

View File

@ -5,25 +5,49 @@
<div class="controls tag-controls">
<label>{{d-icon "d-watching" class="icon watching"}} {{i18n 'user.watched_tags'}}</label>
{{tag-chooser tags=model.watched_tags blacklist=selectedTags allowCreate=false placeholder="" everyTag="true" unlimitedTagCount="true"}}
{{tag-chooser
tags=model.watched_tags
blacklist=selectedTags
filterPlaceholder=null
allowCreate=false
everyTag=true
unlimitedTagCount=true}}
</div>
<div class="instructions">{{i18n 'user.watched_tags_instructions'}}</div>
<div class="controls tag-controls">
<label>{{d-icon "d-regular" class="icon tracking"}} {{i18n 'user.tracked_tags'}}</label>
{{tag-chooser tags=model.tracked_tags blacklist=selectedTags allowCreate=false placeholder="" everyTag="true" unlimitedTagCount="true"}}
{{tag-chooser
tags=model.tracked_tags
blacklist=selectedTags
filterPlaceholder=null
allowCreate=false
everyTag=true
unlimitedTagCount=true}}
</div>
<div class="instructions">{{i18n 'user.tracked_tags_instructions'}}</div>
<div class="controls tag-controls">
<label>{{d-icon "d-watching-first" class="icon watching-first-post"}} {{i18n 'user.watched_first_post_tags'}}</label>
{{tag-chooser tags=model.watching_first_post_tags blacklist=selectedTags allowCreate=false placeholder="" everyTag="true" unlimitedTagCount="true"}}
{{tag-chooser
tags=model.watching_first_post_tags
blacklist=selectedTags
filterPlaceholder=null
allowCreate=false
everyTag=true
unlimitedTagCount=true}}
</div>
<div class="instructions">{{i18n 'user.watched_first_post_tags_instructions'}}</div>
<div class="controls tag-controls">
<label>{{d-icon "d-muted" class="icon muted"}} {{i18n 'user.muted_tags'}}</label>
{{tag-chooser tags=model.muted_tags blacklist=selectedTags allowCreate=false placeholder="" everyTag="true" unlimitedTagCount="true"}}
{{tag-chooser
tags=model.muted_tags
blacklist=selectedTags
filterPlaceholder=null
allowCreate=false
everyTag=true
unlimitedTagCount=true}}
</div>
<div class="instructions">{{i18n 'user.muted_tags_instructions'}}</div>

View File

@ -3,12 +3,19 @@
<br/>
<section class="group-tags-list">
<label>{{i18n 'tagging.groups.tags_label'}}</label><br/>
{{tag-chooser tags=model.tag_names everyTag="true" unlimitedTagCount="true"}}
{{tag-chooser
tags=model.tag_names
everyTag=true
unlimitedTagCount=true}}
</section>
<section class="parent-tag-section">
<label>{{i18n 'tagging.groups.parent_tag_label'}}</label>
{{tag-chooser tags=model.parent_tag_name everyTag="true" limit="1" placeholderKey="tagging.groups.parent_tag_placeholder"}}
{{tag-chooser
tags=model.parent_tag_name
everyTag=true
limit=1
filterPlaceholder="tagging.groups.parent_tag_placeholder"}}
<span class="description">{{i18n 'tagging.groups.parent_tag_description'}}</span>
</section>

View File

@ -22,7 +22,7 @@
{{/if}}
{{#if canEditTags}}
{{tag-chooser tags=buffered.tags categoryId=buffered.category_id}}
{{mini-tag-chooser tags=buffered.tags categoryId=buffered.category_id}}
{{/if}}
{{plugin-outlet name="edit-topic" args=(hash model=model buffered=buffered)}}

View File

@ -1,22 +1,22 @@
import ComboBox from "select-kit/components/combo-box";
import { ajax } from "discourse/lib/ajax";
import { popupAjaxError } from 'discourse/lib/ajax-error';
import Tags from "select-kit/mixins/tags";
import { default as computed } from "ember-addons/ember-computed-decorators";
import renderTag from "discourse/lib/render-tag";
const { get, isEmpty, isPresent, run, makeArray } = Ember;
const { get, isEmpty, run, makeArray } = Ember;
export default ComboBox.extend({
export default ComboBox.extend(Tags, {
allowContentReplacement: true,
pluginApiIdentifiers: ["mini-tag-chooser"],
attributeBindings: ["categoryId"],
classNames: ["mini-tag-chooser"],
classNameBindings: ["noTags"],
verticalOffset: 3,
filterable: true,
noTags: Ember.computed.empty("computedTags"),
noTags: Ember.computed.empty("selectedTags"),
allowAny: true,
maximumSelectionSize: Ember.computed.alias("siteSettings.max_tags_per_topic"),
caretUpIcon: Ember.computed.alias("caretIcon"),
caretDownIcon: Ember.computed.alias("caretIcon"),
isAsync: true,
init() {
this._super();
@ -30,17 +30,8 @@ export default ComboBox.extend({
noHref: true
});
});
},
@computed("limitReached", "maximumSelectionSize")
maxContentRow(limitReached, count) {
if (limitReached) {
return I18n.t("select_kit.max_content_reached", { count });
}
},
mutateAttributes() {
this.set("value", null);
this.set("limit", parseInt(this.get("limit") || this.get("siteSettings.max_tags_per_topic")));
},
@computed("limitReached")
@ -48,9 +39,9 @@ export default ComboBox.extend({
return limitReached ? null : "plus";
},
@computed("computedTags.[]", "maximumSelectionSize")
limitReached(computedTags, maximumSelectionSize) {
if (computedTags.length >= maximumSelectionSize) {
@computed("selectedTags.[]", "limit")
limitReached(selectedTags, limit) {
if (selectedTags.length >= limit) {
return true;
}
@ -58,33 +49,10 @@ export default ComboBox.extend({
},
@computed("tags")
computedTags(tags) {
selectedTags(tags) {
return makeArray(tags);
},
validateCreate(term) {
if (this.get("limitReached") || !this.site.get("can_create_tag")) {
return false;
}
const filterRegexp = new RegExp(this.site.tags_filter_regexp, "g");
term = term.replace(filterRegexp, "").trim().toLowerCase();
if (!term.length || this.get("termMatchesForbidden")) {
return false;
}
if (this.get("siteSettings.max_tag_length") < term.length) {
return false;
}
return true;
},
validateSelect() {
return this.get("computedTags").length < this.get("siteSettings.max_tags_per_topic");
},
filterComputedContent(computedContent) {
return computedContent;
},
@ -92,7 +60,7 @@ export default ComboBox.extend({
didRender() {
this._super();
this.$().on("click.mini-tag-chooser", ".selected-tag", (event) => {
$(".select-kit-body").on("click.mini-tag-chooser", ".selected-tag", (event) => {
event.stopImmediatePropagation();
this.send("removeTag", $(event.target).attr("data-value"));
});
@ -102,9 +70,6 @@ export default ComboBox.extend({
this._super();
$(".select-kit-body").off("click.mini-tag-chooser");
const searchDebounce = this.get("searchDebounce");
if (isPresent(searchDebounce)) { run.cancel(searchDebounce); }
},
didPressEscape(event) {
@ -167,9 +132,9 @@ export default ComboBox.extend({
computeHeaderContent() {
let content = this.baseHeaderComputedContent();
const joinedTags = this.get("computedTags").join(", ");
const joinedTags = this.get("selectedTags").join(", ");
if (isEmpty(this.get("computedTags"))) {
if (isEmpty(this.get("selectedTags"))) {
content.label = I18n.t("tagging.choose_for_topic");
} else {
content.label = joinedTags;
@ -182,80 +147,61 @@ export default ComboBox.extend({
actions: {
removeTag(tag) {
let tags = this.get("computedTags");
let tags = this.get("selectedTags");
delete tags[tags.indexOf(tag)];
this.set("tags", tags.filter(t => t));
this.set("content", []);
this.set("searchDebounce", run.debounce(this, this._searchTags, this.get("filter"), 250));
this.set("searchDebounce", run.debounce(this, this.prepareSearch, this.get("filter"), 200));
},
onExpand() {
if (isEmpty(this.get("content"))) {
this.set("searchDebounce", run.debounce(this, this._searchTags, this.get("filter"), 250));
if (isEmpty(this.get("collectionComputedContent"))) {
this.set("searchDebounce", run.debounce(this, this.prepareSearch, this.get("filter"), 200));
}
},
onFilter(filter) {
filter = isEmpty(filter) ? null : filter;
this.set("searchDebounce", run.debounce(this, this._searchTags, filter, 250));
this.set("searchDebounce", run.debounce(this, this.prepareSearch, filter, 200));
},
onSelect(tag) {
if (isEmpty(this.get("computedTags"))) {
if (isEmpty(this.get("selectedTags"))) {
this.set("tags", makeArray(tag));
} else {
this.set("tags", this.get("computedTags").concat(tag));
this.set("tags", this.get("selectedTags").concat(tag));
}
this.set("content", []);
this.set("searchDebounce", run.debounce(this, this._searchTags, this.get("filter"), 250));
this.set("searchDebounce", run.debounce(this, this.prepareSearch, this.get("filter"), 50));
this.autoHighlight();
}
},
_searchTags(query) {
this.startLoading();
const self = this;
const selectedTags = makeArray(this.get("computedTags")).filter(t => t);
const sortTags = this.siteSettings.tags_sort_alphabetically;
prepareSearch(query) {
const data = {
q: query,
limit: this.siteSettings.max_tag_search_results,
limit: this.get("siteSettings.max_tag_search_results"),
categoryId: this.get("categoryId")
};
if (this.get("selectedTags")) data.selected_tags = this.get("selectedTags").slice(0, 100);
if (!this.get("everyTag")) data.filterForInput = true;
if (selectedTags) {
data.selected_tags = selectedTags.slice(0, 100);
this.searchTags("/tags/filter/search", data, this._transformJson);
},
_transformJson(context, json) {
let results = json.results;
context.set("termMatchesForbidden", json.forbidden ? true : false);
if (context.get("siteSettings.tags_sort_alphabetically")) {
results = results.sort((a, b) => a.id > b.id);
}
ajax(Discourse.getURL("/tags/filter/search"), {
quietMillis: 200,
cache: true,
dataType: "json",
data,
}).then(json => {
let results = json.results;
results = results.filter(r => !context.get("selectedTags").includes(r.id));
self.set("termMatchesForbidden", json.forbidden ? true : false);
if (sortTags) {
results = results.sort((a, b) => a.id > b.id);
}
const content = results.map((result) => {
return {
id: result.text,
name: result.text,
count: result.count
};
}).filter(c => !selectedTags.includes(c.id));
self.set("content", content);
self.stopLoading();
this.autoHighlight();
}).catch(error => {
self.stopLoading();
popupAjaxError(error);
});
return results.map(result => {
return { id: result.text, name: result.text, count: result.count };
});
}
});

View File

@ -8,14 +8,15 @@ import {
export default SelectKitComponent.extend({
pluginApiIdentifiers: ["multi-select"],
layoutName: "select-kit/templates/components/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",
filterIcon: null,
init() {
this._super();
@ -38,16 +39,22 @@ export default SelectKitComponent.extend({
_compute() {
Ember.run.scheduleOnce("afterRender", () => {
this.willComputeAttributes();
let content = this.willComputeContent(this.get("content") || []);
let content = this.get("content") || [];
let asyncContent = this.get("asyncContent") || [];
content = this.willComputeContent(content);
asyncContent = this.willComputeAsyncContent(asyncContent);
let values = this._beforeWillComputeValues(this.get("values"));
content = this.computeContent(content);
asyncContent = this.computeAsyncContent(asyncContent);
content = this._beforeDidComputeContent(content);
asyncContent = this._beforeDidComputeAsyncContent(asyncContent);
values = this.willComputeValues(values);
values = this.computeValues(values);
values = this._beforeDidComputeValues(values);
this._setHeaderComputedContent();
this._setCollectionHeaderComputedContent();
this.didComputeContent(content);
this.didComputeAsyncContent(asyncContent);
this.didComputeValues(values);
this.didComputeAttributes();
});
@ -102,6 +109,19 @@ export default SelectKitComponent.extend({
});
},
@computed("computedAsyncContent.[]", "computedValues.[]")
filteredAsyncComputedContent(computedAsyncContent, computedValues) {
computedAsyncContent = computedAsyncContent.filter(c => {
return !computedValues.includes(get(c, "value"));
});
if (this.get("limitMatches")) {
return computedAsyncContent.slice(0, this.get("limitMatches"));
}
return computedAsyncContent;
},
@computed("computedContent.[]", "computedValues.[]", "filter")
filteredComputedContent(computedContent, computedValues, filter) {
computedContent = computedContent.filter(c => {
@ -133,6 +153,16 @@ export default SelectKitComponent.extend({
};
},
@computed("limit", "computedValues.[]")
limitReached(limit, computedValues) {
if (!limit) return false;
return computedValues.length >= limit;
},
validateSelect() {
return this._super() && !this.get("limitReached");
},
didPressBackspace(event) {
this.expand(event);
this.keyDown(event);
@ -178,16 +208,16 @@ export default SelectKitComponent.extend({
if ($lastSelectedValue.length === 0) { return; }
if ($filterInput.not(":visible") && $lastSelectedValue.length > 0) {
$lastSelectedValue.click();
$lastSelectedValue.trigger("backspace");
return false;
}
if ($filterInput.val() === "") {
if ($filterInput.is(":focus")) {
if ($lastSelectedValue.length > 0) { $lastSelectedValue.click(); }
if ($lastSelectedValue.length > 0) { $lastSelectedValue.trigger("backspace"); }
} else {
if ($lastSelectedValue.length > 0) {
$lastSelectedValue.click();
$lastSelectedValue.trigger("backspace");
} else {
$filterInput.focus();
}
@ -217,14 +247,14 @@ export default SelectKitComponent.extend({
if (!this.get("renderedBodyOnce")) return;
if (!isNone(this.get("highlightedValue"))) return;
if (isEmpty(this.get("filteredComputedContent"))) {
if (isEmpty(this.get("collectionComputedContent"))) {
if (this.get("createRowComputedContent")) {
this.send("highlight", this.get("createRowComputedContent"));
} else if (this.get("noneRowComputedContent") && this.get("hasSelection")) {
this.send("highlight", this.get("noneRowComputedContent"));
}
} else {
this.send("highlight", this.get("filteredComputedContent.firstObject"));
this.send("highlight", this.get("collectionComputedContent.firstObject"));
}
});
},
@ -247,9 +277,10 @@ export default SelectKitComponent.extend({
this.set("highlightedValue", null);
},
didDeselect() {
didDeselect(rowComputedContentItems) {
this.focusFilterOrHeader();
this.autoHighlight();
this._boundaryActionHandler("onDeselect", rowComputedContentItems);
},
actions: {

View File

@ -28,6 +28,20 @@ export default Ember.Component.extend({
return null;
},
didInsertElement() {
this._super();
$(this.element).on("backspace.selected-name", () => {
this._handleBackspace();
});
},
willDestroyElement() {
this._super();
$(this.element).off("backspace.selected-name");
},
label: Ember.computed.or("computedContent.label", "title", "name"),
name: Ember.computed.alias("computedContent.name"),
@ -39,8 +53,18 @@ export default Ember.Component.extend({
}),
click() {
if (this.get("isLocked") === true) { return false; }
this.toggleProperty("isHighlighted");
if (this.get("isLocked") === true) return false;
this.sendAction("deselect", [this.get("computedContent")]);
return false;
},
_handleBackspace() {
if (this.get("isLocked") === true) return false;
if (this.get("isHighlighted")) {
this.sendAction("deselect", [this.get("computedContent")]);
} else {
this.set("isHighlighted", true);
}
}
});

View File

@ -32,6 +32,7 @@ export default Ember.Component.extend(UtilsMixin, PluginApiMixin, DomHelpersMixi
isFocused: false,
isHidden: false,
isLoading: false,
isAsync: false,
renderedBodyOnce: false,
renderedFilterOnce: false,
tabindex: 0,
@ -69,8 +70,6 @@ export default Ember.Component.extend(UtilsMixin, PluginApiMixin, DomHelpersMixi
allowContentReplacement: false,
collectionHeader: null,
allowAutoSelectFirst: true,
maximumSelectionSize: null,
maxContentRow: null,
init() {
this._super();
@ -91,11 +90,16 @@ export default Ember.Component.extend(UtilsMixin, PluginApiMixin, DomHelpersMixi
if (this.get("allowContentReplacement")) {
this.addObserver(`content.[]`, this, this._compute);
}
if (this.get("isAsync")) {
this.addObserver(`asyncContent.[]`, this, this._compute);
}
},
willDestroyElement() {
this.removeObserver(`content.@each.${this.get("nameProperty")}`, this, this._compute);
this.removeObserver(`content.[]`, this, this._compute);
this.removeObserver(`asyncContent.[]`, this, this._compute);
},
willComputeAttributes() {},
@ -114,6 +118,17 @@ export default Ember.Component.extend(UtilsMixin, PluginApiMixin, DomHelpersMixi
},
didComputeContent() {},
willComputeAsyncContent(content) { return content; },
computeAsyncContent(content) { return content; },
_beforeDidComputeAsyncContent(content) {
content = applyContentPluginApiCallbacks(this.get("pluginApiIdentifiers"), content, this);
this.setProperties({
computedAsyncContent: content.map(c => this.computeAsyncContentItem(c))
});
return content;
},
didComputeAsyncContent() {},
computeHeaderContent() {
return this.baseHeaderComputedContent();
},
@ -122,6 +137,15 @@ export default Ember.Component.extend(UtilsMixin, PluginApiMixin, DomHelpersMixi
return this.baseComputedContentItem(contentItem, options);
},
computeAsyncContentItem(contentItem, options) {
return this.computeContentItem(contentItem, options);
},
@computed("isAsync", "filteredAsyncComputedContent", "filteredComputedContent")
collectionComputedContent(isAsync, filteredAsyncComputedContent, filteredComputedContent) {
return isAsync ? filteredAsyncComputedContent : filteredComputedContent;
},
validateCreate() { return true; },
validateSelect() { return true; },
@ -155,13 +179,20 @@ export default Ember.Component.extend(UtilsMixin, PluginApiMixin, DomHelpersMixi
return false;
},
@computed("filter", "filteredComputedContent.[]")
noContentRow(filter, filteredComputedContent) {
if (filter.length > 0 && filteredComputedContent.length === 0) {
@computed("filter", "collectionComputedContent.[]")
noContentRow(filter, collectionComputedContent) {
if (filter.length > 0 && collectionComputedContent.length === 0) {
return I18n.t("select_kit.no_content");
}
},
@computed("limitReached", "limit")
maxContentRow(limitReached, limit) {
if (limitReached) {
return I18n.t("select_kit.max_content_reached", { count: limit });
}
},
@computed("filter", "filterable", "autoFilterable", "renderedFilterOnce")
shouldFilter(filter, filterable, autoFilterable, renderedFilterOnce) {
if (renderedFilterOnce && filterable) return true;
@ -170,8 +201,9 @@ export default Ember.Component.extend(UtilsMixin, PluginApiMixin, DomHelpersMixi
return false;
},
@computed("filter", "computedContent")
shouldDisplayCreateRow(filter, computedContent) {
@computed("filter", "computedContent", "limitReached")
shouldDisplayCreateRow(filter, computedContent, limitReached) {
if (limitReached) return false;
if (computedContent.map(c => c.value).includes(filter)) return false;
if (this.get("allowAny") && filter.length > 0 && this.validateCreate(filter)) return true;
return false;

View File

@ -1,6 +1,15 @@
import computed from "ember-addons/ember-computed-decorators";
const { isEmpty } = Ember;
export default Ember.Component.extend({
layoutName: "select-kit/templates/components/select-kit/select-kit-filter",
classNames: ["select-kit-filter"],
classNameBindings: ["isFocused", "isHidden"],
isHidden: Ember.computed.not("shouldDisplayFilter")
isHidden: Ember.computed.not("shouldDisplayFilter"),
@computed("placeholder", "hasSelection")
computedPlaceholder(placeholder, hasSelection) {
if (hasSelection) return "";
return isEmpty(placeholder) ? "" : I18n.t(placeholder);
}
});

View File

@ -4,6 +4,7 @@ const { get, isNone, isEmpty, isPresent, run } = Ember;
export default SelectKitComponent.extend({
pluginApiIdentifiers: ["single-select"],
layoutName: "select-kit/templates/components/single-select",
classNames: "single-select",
computedValue: null,
value: null,
@ -13,14 +14,20 @@ export default SelectKitComponent.extend({
_compute() {
run.scheduleOnce("afterRender", () => {
this.willComputeAttributes();
let content = this.willComputeContent(this.get("content") || []);
let content = this.get("content") || [];
let asyncContent = this.get("asyncContent") || [];
content = this.willComputeContent(content);
asyncContent = this.willComputeAsyncContent(asyncContent);
let value = this._beforeWillComputeValue(this.get("value"));
content = this.computeContent(content);
asyncContent = this.computeAsyncContent(asyncContent);
content = this._beforeDidComputeContent(content);
asyncContent = this._beforeDidComputeAsyncContent(asyncContent);
value = this.willComputeValue(value);
value = this.computeValue(value);
value = this._beforeDidComputeValue(value);
this.didComputeContent(content);
this.didComputeAsyncContent(asyncContent);
this.didComputeValue(value);
this.didComputeAttributes();
@ -86,6 +93,19 @@ export default SelectKitComponent.extend({
};
},
@computed("computedAsyncContent.[]", "computedValue")
filteredAsyncComputedContent(computedAsyncContent, computedValue) {
computedAsyncContent = computedAsyncContent.filter(c => {
return computedValue !== get(c, "value");
});
if (this.get("limitMatches")) {
return computedAsyncContent.slice(0, this.get("limitMatches"));
}
return computedAsyncContent;
},
@computed("computedContent.[]", "computedValue", "filter", "shouldFilter")
filteredComputedContent(computedContent, computedValue, filter, shouldFilter) {
if (shouldFilter) {

View File

@ -0,0 +1,107 @@
import MultiSelectComponent from "select-kit/components/multi-select";
import Tags from "select-kit/mixins/tags";
import renderTag from "discourse/lib/render-tag";
import computed from "ember-addons/ember-computed-decorators";
const { get, isEmpty, run, makeArray } = Ember;
export default MultiSelectComponent.extend(Tags, {
pluginApiIdentifiers: ["tag-chooser"],
classNames: "tag-chooser",
isAsync: true,
filterable: true,
filterPlaceholder: "tagging.choose_for_topic",
limit: null,
attributeBindings: ["categoryId"],
allowAny: Ember.computed.alias("allowCreate"),
init() {
this._super();
if (this.get("allowCreate") !== false) {
this.set("allowCreate", this.get("siteSettings.can_create_tag"));
}
this.set("termMatchesForbidden", false);
this.set("templateForRow", (rowComponent) => {
const tag = rowComponent.get("computedContent");
return renderTag(get(tag, "value"), {
count: get(tag, "originalContent.count"),
noHref: true
});
});
if (!this.get("unlimitedTagCount")) {
this.set("limit", parseInt(this.get("limit") || this.get("siteSettings.max_tags_per_topic")));
}
},
mutateValues(values) {
this.set("tags", values.filter(v => v));
},
@computed("tags")
values(tags) {
return makeArray(tags);
},
@computed("tags")
content(tags) {
return makeArray(tags);
},
actions: {
onFilter(filter) {
this.expand();
this.set("searchDebounce", run.debounce(this, this.prepareSearch, filter, 200));
},
onExpand() {
if (isEmpty(this.get("collectionComputedContent"))) {
this.set("searchDebounce", run.debounce(this, this.prepareSearch, this.get("filter"), 200));
}
},
onDeselect() {
this.set("searchDebounce", run.debounce(this, this.prepareSearch, this.get("filter"), 200));
},
onSelect() {
this.set("searchDebounce", run.debounce(this, this.prepareSearch, this.get("filter"), 50));
}
},
prepareSearch(query) {
const selectedTags = makeArray(this.get("values")).filter(t => t);
const data = {
q: query,
limit: this.get("siteSettings.max_tag_search_results"),
categoryId: this.get("categoryId")
};
if (selectedTags) data.selected_tags = selectedTags.slice(0, 100);
if (!this.get("everyTag")) data.filterForInput = true;
this.searchTags("/tags/filter/search", data, this._transformJson);
},
_transformJson(context, json) {
let results = json.results;
context.set("termMatchesForbidden", json.forbidden ? true : false);
if (context.get("blacklist")) {
results = results.filter(result => {
return !context.get("blacklist").includes(result.id);
});
}
if (context.get("siteSettings.tags_sort_alphabetically")) {
results = results.sort((a, b) => a.id > b.id);
}
return results.map(result => {
return { id: result.text, name: result.text, count: result.count };
});
}
});

View File

@ -0,0 +1,79 @@
import MultiSelectComponent from "select-kit/components/multi-select";
import Tags from "select-kit/mixins/tags";
import renderTag from "discourse/lib/render-tag";
import computed from "ember-addons/ember-computed-decorators";
const { get, isEmpty, run, makeArray } = Ember;
export default MultiSelectComponent.extend(Tags, {
pluginApiIdentifiers: ["tag-group-chooser"],
classNames: ["tag-group-chooser", "tag-chooser"],
isAsync: true,
filterable: true,
filterPlaceholder: "category.tag_groups_placeholder",
limit: null,
allowAny: false,
init() {
this._super();
this.set("templateForRow", (rowComponent) => {
const tag = rowComponent.get("computedContent");
return renderTag(get(tag, "value"), {
count: get(tag, "originalContent.count"),
noHref: true
});
});
},
mutateValues(values) {
this.set("tagGroups", values.filter(v => v));
},
@computed("tagGroups")
values(tagGroups) {
return makeArray(tagGroups);
},
@computed("tagGroups")
content(tagGroups) {
return makeArray(tagGroups);
},
actions: {
onFilter(filter) {
this.expand();
this.set("searchDebounce", run.debounce(this, this.prepareSearch, filter, 200));
},
onExpand() {
if (isEmpty(this.get("collectionComputedContent"))) {
this.set("searchDebounce", run.debounce(this, this.prepareSearch, this.get("filter"), 200));
}
},
onDeselect() {
this.set("searchDebounce", run.debounce(this, this.prepareSearch, this.get("filter"), 200));
},
onSelect() {
this.set("searchDebounce", run.debounce(this, this.prepareSearch, this.get("filter"), 50));
}
},
prepareSearch(query) {
const data = {
q: query,
limit: this.get("siteSettings.max_tag_search_results")
};
this.searchTags("/tags/filter/search", data, this._transformJson);
},
_transformJson(context, json) {
let results = json.results.sort((a, b) => a.id > b.id);
return results.map(result => {
return { id: result.text, name: result.text, count: result.count };
});
},
});

View File

@ -0,0 +1,52 @@
const { run } = Ember;
import { ajax } from "discourse/lib/ajax";
import { popupAjaxError } from "discourse/lib/ajax-error";
export default Ember.Mixin.create({
willDestroyElement() {
this._super();
const searchDebounce = this.get("searchDebounce");
if (searchDebounce) run.cancel(searchDebounce);
},
searchTags(url, data, callback) {
const self = this;
this.startLoading();
return ajax(Discourse.getURL(url), {
quietMillis: 200,
cache: true,
dataType: "json",
data
}).then(json => {
self.set("asyncContent", callback(self, json));
}).catch(error => {
popupAjaxError(error);
})
.finally(() => {
self.stopLoading();
self.autoHighlight();
});
},
validateCreate(term) {
if (this.get("limitReached") || !this.site.get("can_create_tag")) {
return false;
}
const filterRegexp = new RegExp(this.site.tags_filter_regexp, "g");
term = term.replace(filterRegexp, "").trim().toLowerCase();
if (!term.length || this.get("termMatchesForbidden")) {
return false;
}
if (this.get("siteSettings.max_tag_length") < term.length) {
return false;
}
return true;
},
});

View File

@ -0,0 +1,50 @@
{{#component headerComponent
tabindex=tabindex
isFocused=isFocused
isExpanded=isExpanded
computedContent=headerComputedContent
deselect=(action "deselect")
toggle=(action "toggle")
clearSelection=(action "clearSelection")
options=headerComponentOptions
}}
{{component filterComponent
icon=filterIcon
placeholder=filterPlaceholder
filter=filter
hasSelection=hasSelection
isLoading=isLoading
shouldDisplayFilter=shouldDisplayFilter
isFocused=isFocused
filterComputedContent=(action "filterComputedContent")
}}
{{/component}}
<div class="select-kit-body">
{{#if renderedBodyOnce}}
{{component collectionComponent
collectionHeaderComputedContent=collectionHeaderComputedContent
hasSelection=hasSelection
noneRowComputedContent=noneRowComputedContent
createRowComputedContent=createRowComputedContent
collectionComputedContent=collectionComputedContent
rowComponent=rowComponent
noneRowComponent=noneRowComponent
createRowComponent=createRowComponent
templateForRow=templateForRow
templateForNoneRow=templateForNoneRow
templateForCreateRow=templateForCreateRow
clearSelection=(action "clearSelection")
select=(action "select")
highlight=(action "highlight")
create=(action "create")
highlightedValue=highlightedValue
computedValue=computedValue
rowComponentOptions=rowComponentOptions
noContentRow=noContentRow
maxContentRow=maxContentRow
}}
{{/if}}
</div>
<div class="select-kit-wrapper"></div>

View File

@ -5,11 +5,6 @@
computedContent=selectedComputedContent}}
{{/each}}
<span class="filter choice" tabindex="-1">
{{component "select-kit/select-kit-filter"
filterComputedContent=filterComputedContent
shouldDisplayFilter=shouldDisplayFilter
isFocused=isFocused
filter=filter
}}
{{yield}}
</span>
</div>

View File

@ -1,7 +1,3 @@
<div class="body">
<span class="delete-icon" {{action deselect computedContent bubbles=false}}>
{{d-icon "times"}}
</span>
{{badge}}
</div>

View File

@ -1,16 +1,6 @@
{{#if headerContent}}<div class="header">{{headerContent}}</div>{{/if}}
<div class="body">
{{#if isLocked}}
<span class="delete-icon">
{{d-icon "lock"}}
</span>
{{else}}
<span class="locked-icon" {{action deselect computedContent bubbles=false}}>
{{d-icon "times"}}
</span>
{{/if}}
<span class="name">
{{{label}}}
</span>

View File

@ -40,7 +40,7 @@
{{noContentRow}}
</li>
{{else}}
{{#each filteredComputedContent as |computedContent|}}
{{#each collectionComputedContent as |computedContent|}}
{{component rowComponent
computedContent=computedContent
highlightedValue=highlightedValue

View File

@ -1,7 +1,7 @@
{{input
tabindex=-1
class="filter-input"
placeholder=placeholder
placeholder=computedPlaceholder
key-up=filterComputedContent
autocomplete="off"
autocorrect="off"

View File

@ -1,13 +1,10 @@
{{component headerComponent
tabindex=tabindex
shouldDisplayFilter=shouldDisplayFilter
isFocused=isFocused
isExpanded=isExpanded
computedContent=headerComputedContent
deselect=(action "deselect")
toggle=(action "toggle")
isLoading=isLoading
filterComputedContent=(action "filterComputedContent")
clearSelection=(action "clearSelection")
options=headerComponentOptions
}}
@ -17,8 +14,9 @@
filter=filter
isLoading=isLoading
icon=filterIcon
hasSelection=hasSelection
shouldDisplayFilter=shouldDisplayFilter
placeholder=(i18n filterPlaceholder)
placeholder=filterPlaceholder
isFocused=isFocused
filterComputedContent=(action "filterComputedContent")
}}
@ -29,7 +27,7 @@
hasSelection=hasSelection
noneRowComputedContent=noneRowComputedContent
createRowComputedContent=createRowComputedContent
filteredComputedContent=filteredComputedContent
collectionComputedContent=collectionComputedContent
rowComponent=rowComponent
noneRowComponent=noneRowComponent
createRowComponent=createRowComponent

View File

@ -14,7 +14,6 @@
//= require bootstrap-dropdown.js
//= require bootstrap-modal.js
//= require bootstrap-transition.js
//= require select2.js
//= require div_resizer
//= require caret_position
//= require favcount.js

View File

@ -1,5 +1,4 @@
//= require template_include.js
//= require select2.js
//= require jquery.ui.widget.js
//= require jquery.fileupload.js
//= require sweetalert.js

View File

@ -3,7 +3,6 @@
@import "vendor/pikaday";
@import "common/foundation/helpers";
@import "common/foundation/base";
@import "vendor/select2";
@import "common/foundation/mixins";
@import "common/foundation/variables";
@import "common/select-kit/*";

View File

@ -270,7 +270,7 @@ $mobile-breakpoint: 700px;
@include clearfix;
nav {
float: left;
margin-left: 12px;
margin-left: 12px;
}
.nav.nav-pills {
li.active {
@ -493,9 +493,6 @@ $mobile-breakpoint: 700px;
width: 100% !important; // !important overrides hard-coded mobile width of 68px
}
}
.select2-container-multi .select2-choices {
border: none;
}
}
.setting-controls {
float: left;
@ -521,13 +518,6 @@ $mobile-breakpoint: 700px;
border-radius: 3px;
transition: border linear 0.2s, box-shadow linear 0.2s;
li.select2-search-choice {
cursor: pointer;
.select2-search-choice-close {
content: "x"
}
}
li.sortable-placeholder {
padding: 3px 5px 3px 18px;
margin: 3px 0 3px 5px;
@ -831,14 +821,6 @@ section.details {
.controls {
margin-top: 10px;
}
.select2-container {
width: 100%;
}
.select2-choices {
width: 100%;
border-color: dark-light-choose($primary-low-mid, $secondary-high);
}
.content-list {
margin-right: 20px;
}

View File

@ -36,7 +36,7 @@
.admin-footer {
margin-top: 20px;
}
.select2-chosen, .color-schemes li {
.color-schemes li {
.fa {
margin-right: 6px;
color: dark-light-choose($primary-medium, $secondary-medium);

View File

@ -229,10 +229,6 @@
margin: 0;
flex: 1 1 100%;
}
&.select2-dropdown-open, &.select2-container-active {
border-color: $tertiary;
}
}
.wmd-controls {

View File

@ -88,6 +88,10 @@
.select-kit {
width: 220px;
&.tag-chooser {
width: 100%;
}
}
}

View File

@ -92,7 +92,7 @@
}
.search-bar {
display: flex;
display: flex;
margin-bottom: 10px;
max-width: 780px;
input {
@ -122,7 +122,7 @@
position: relative;
margin: 10px 0 15px;
max-width: 780px;
border-bottom: 3px solid $primary-low;
border-bottom: 3px solid $primary-low;
width: 100%;
.term {
font-weight: bold;
@ -130,7 +130,7 @@
.result-count {
float: left;
margin-bottom: 4px;
margin-bottom: 4px;
span {
line-height: $line-height-large;
height: 28px;
@ -163,7 +163,7 @@
max-width: 780px;
.search-advanced-options {
border: 1px solid $primary-low;
padding: 0 20px;
padding: 0 20px;
width: 100%;
.date-picker-wrapper {
vertical-align: top;
@ -183,6 +183,10 @@
font-weight: bold;
}
.tag-chooser {
width: 70%;
}
.container {
display: flex;
flex: 1 1 100%;
@ -206,4 +210,4 @@
}
}
}
}
}

View File

@ -25,8 +25,8 @@
.tag-count {
font-size: $font-down-1;
vertical-align: middle;
line-height: $line-height-small;
vertical-align: middle;
line-height: $line-height-small;
}
}
@ -61,7 +61,7 @@
&.box, &.bullet {
}
&.box + .topic-header-extra,
&.bullet + .topic-header-extra,
&.bar + .topic-header-extra {
@ -69,25 +69,17 @@
}
}
.add-tags .select2 {
margin: 0;
}
$tag-color: $primary-medium;
.discourse-tag-count {
font-size: $font-down-1;
color: $tag-color;
line-height: $line-height-small;
vertical-align: middle;
}
.select2-result-label .discourse-tag {
margin-right: 0;
vertical-align: middle;
}
.discourse-tag {
max-width: 14em;
max-width: 14em;
display: inline-block;
white-space: nowrap;
overflow: hidden;
@ -131,29 +123,13 @@ $tag-color: $primary-medium;
}
.d-header .topic-header-extra {
.discourse-tags {
.discourse-tags {
display: inline-block;
font-size: $font-down-1;
font-size: $font-down-1;
}
.topic-featured-link { margin-left: 8px; }
}
.select2-container-multi .select2-choices .select2-search-choice.discourse-tag-select2 {
-webkit-box-shadow: none;
box-shadow: none;
border: 0;
border-radius: 0;
background-color: transparent;
.discourse-tag {
padding: 4px;
&.box {
padding: 1px 8px;
margin: 3px 5px;
}
}
}
.fps-result .add-full-page-tags {
display: inline-block;
}
@ -213,11 +189,6 @@ header .discourse-tag {color: $tag-color }
width: 100%;
max-width: 100%;
margin: 5px 0;
ul.select2-choices {
max-height: 30px;
padding-left: 10px;
overflow-y: auto;
}
}
.title-wrapper .tag-chooser {
@ -278,11 +249,7 @@ header .discourse-tag {color: $tag-color }
}
}
.group-tags-list .tag-chooser {
height: 250px !important;
ul.select2-choices {
height: 250px !important; // to fight with select2.scss's important
max-height: none;
}
width: 100%;
}
.btn {margin-left: 10px;}
.saving {

View File

@ -105,15 +105,15 @@ a.badge-category {
.private-message-glyph {
margin: 5px 5px 0 0;
}
.category-chooser, .tag-chooser {
.category-chooser, .mini-tag-chooser {
flex: 1 1 49%;
margin: 0 0 9px 0;
@media all and (max-width: 500px) {
flex: 1 1 100%;
flex: 1 1 100%;
}
}
.tag-chooser {
.mini-tag-chooser {
margin-left: 2%;
@media all and (max-width: 500px) {
margin-left: 0;
@ -204,7 +204,7 @@ a.badge-category {
.post-links {
margin-top: 1em;
padding-top: 1em;
border-top: 1px solid $primary-low;
border-top: 1px solid $primary-low;
li:last-of-type {
margin-bottom: 1em;
}

View File

@ -198,9 +198,9 @@
.staff-counters {
background: $primary;
color: $secondary;
color: $secondary;
display: flex;
padding: 10px;
padding: 10px;
> div, > div a {
display: flex;
align-items: baseline;
@ -209,9 +209,9 @@
span {
padding: 1px 6px;
border-radius: 10px;
margin-right: 5px;
margin-right: 5px;
}
}
}
a {
color: $secondary;
@ -404,7 +404,7 @@
&.linked-stat { // This makes the entire "box" (the li) clickable instead of a narrow area.
padding: 0;
a {
padding: 10px 14px;
padding: 10px 14px;
width: 100%;
height: 100%;
display: block;
@ -519,15 +519,6 @@
.tag-notifications .tag-controls {
margin-top: 24px;
}
.tags .select2-container-multi {
border: 1px solid $primary-low;
width: 540px;
border-radius: 0;
.select2-choices {
border: none;
}
}
}
.paginated-topics-list {

View File

@ -1,88 +0,0 @@
// DO NOT MODIFY
// TODO: remove when all select2 instances are gone
.select2-results .select2-highlighted {
background: $highlight-medium;
color: $primary;
}
.select2-drop {
.badge-category {
display: inline-block;
}
.topic-count {
font-size: $font-down-2;
color: $primary;
display: inline-block;
}
.highlighted .topic-count, .select2-highlighted .category-desc {
color: $primary;
}
.category-desc {
color: $primary;
font-size: $font-down-1;
line-height: 16px;
}
}
.select2-drop {
background: $secondary;
.d-icon {
color: dark-light-choose($primary-medium, $secondary-medium);
}
}
.select2-search input {
background: image-url("select2.png") no-repeat 100% -22px, $secondary 0 0
}
.select2-container {
min-width: 200px;
&.select2-dropdown-open {
border: 0;
margin-bottom: 2px;
}
&.select2-container-active {
border-color: $tertiary;
}
&.select2-container-disabled .select2-chosen {
color: blend-primary-secondary(50%);
}
}
.select2-container-multi .select2-choices .select2-search-field input.select2-active {
background: $secondary image-url("select2-spinner.gif") no-repeat 100% !important;
}
.select2-container-multi .select2-choices {
border: 1px solid $primary-medium;
}
.select2-container a.select2-choice {
background: $secondary;
border-radius: 3px;
border-color: $secondary;
color: $primary;
}
.select2-dropdown-open a.select2-choice {
box-shadow: none;
border-radius: 3px 3px 0 0;
border-color: $tertiary;
}
.select2-drop {
color: $primary;
}
.select2-drop-active {
border: 1px solid $tertiary;
border-top: 0;
}
.select2-container-active {
box-shadow: shadow("focus");
}
.select2-results .select2-no-results, .select2-results .select2-searching, .select2-results .select2-selection-limit {
background: $secondary;
color: $primary;
}

View File

@ -7,7 +7,6 @@
&.is-expanded {
.select-kit-header {
border: 1px solid $tertiary;
box-shadow: shadow("focus");
}
}
@ -59,7 +58,7 @@
}
.selected-tag {
background: $primary-very-low;
background: $primary-low;
padding: 2px 4px;
margin: 2px;
border: 0;

View File

@ -17,6 +17,7 @@
.select-kit-filter {
border: 0;
flex: 1;
}
.multi-select-header {
@ -79,7 +80,7 @@
justify-content: space-between;
flex-wrap: wrap;
flex-direction: row;
margin: 2.5px;
margin: 2px;
}
.filter {
@ -89,6 +90,7 @@
min-width: 50px;
padding: 0;
outline: none;
flex: 1;
.filter-input, .filter-input:focus {
border: none;
@ -117,17 +119,36 @@
.color-preview {
height: 5px;
margin: 0 2px 2px 2px;
border-radius: 5px;
display: flex;
width: 100%;
}
}
.selected-category {
.badge-wrapper {
&.bullet {
margin-right: 2.5px;
}
margin: auto 2.5px;
padding: 2px 4px;
line-height: $line-height-medium;
display: flex;
flex: 1;
align-items: center;
&:after {
content: '\f00d';
color: $primary-low-mid;
font-family: 'FontAwesome';
font-size: $font-down-2;
margin-left: 5px;
}
}
}
.selected-name {
color: $primary;
border: 1px solid $primary-medium;
border-radius: 3px;
box-shadow: 0 0 2px $secondary inset, 0 1px 0 rgba(0,0,0,0.05);
background-clip: padding-box;
-webkit-touch-callout: none;
user-select: none;
@ -148,55 +169,32 @@
}
.body {
width: 100%;
display: inline-flex;
display: flex;
align-items: center;
.locked-icon, .delete-icon {
justify-content: center;
align-items: center;
display: inline-flex;
height: 21px;
width: 21px;
.d-icon {
color: $primary-medium;
cursor: pointer;
font-size: 1em;
margin: 0;
&:hover {
color: $primary;
}
}
}
flex: 1;
}
.name {
padding: 0 5px;
padding: 2px 4px;
line-height: $line-height-medium;
&:after {
content: '\f00d';
color: $primary-low-mid;
font-family: 'FontAwesome';
font-size: $font-down-2;
}
&:hover {
&:after {
color: $danger;
}
}
}
&.is-highlighted {
box-shadow: 0 0 2px $danger, 0 1px 0 rgba(0,0,0,0.05);
}
.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: $font-0;
&:hover {
color: $primary;
}
}
}
}
}
}

View File

@ -202,6 +202,7 @@
border-radius: inherit;
-webkit-overflow-scrolling: touch;
margin: 0;
padding: 0;
max-height: 200px;
.select-kit-collection {

View File

@ -0,0 +1,14 @@
.select-kit {
&.multi-select {
&.tag-chooser {
.select-kit-row {
display: flex;
align-items: center;
.discourse-tag-count {
margin-left: 5px;
}
}
}
}
}

View File

@ -56,14 +56,6 @@
.category-combobox {
width: 430px;
.select2-drop {
left: -9000px;
width: 428px;
}
.select2-search input {
width: 378px;
}
}
}

View File

@ -24,6 +24,15 @@
}
}
.tag-chooser {
width: 100%;
margin-bottom: .5em;
.select-kit-collection {
padding: 0;
}
}
.queue-controls {
button {
float: left;

View File

@ -28,15 +28,12 @@
font-size: $font-up-4;
line-height: $line-height-medium;
overflow: hidden;
width: 100%;
width: 100%;
a {color: $primary;}
}
.topic-statuses {
margin-top: -2px;
}
.select2-container {
vertical-align: middle;
}
.private-message-glyph { display: none; }
.remove-featured-link {
float: right;

View File

@ -279,10 +279,12 @@
width: 530px;
}
.category-selector, .tag-chooser {
width: 530px;
}
input {
&.category-selector,
&.user-selector,
&.tag-chooser {
&.user-selector {
width: 530px;
}

View File

@ -181,11 +181,6 @@ sup sup, sub sup, sup sub, sub sub { top: 0; }
width: 100%;
height: 32px;
}
.select2-container {
box-sizing: border-box;
width: 100% !important;
}
.btn-small {
padding: 6px 12px;
margin: 6px 6px 0 0;

View File

@ -1,575 +0,0 @@
/*
Version: @@ver@@ Timestamp: @@timestamp@@
*/
.select2-container {
margin: 0;
position: relative;
display: inline-block;
/* inline-block for ie7 */
zoom: 1;
vertical-align: middle;
}
.select2-container,
.select2-drop,
.select2-search,
.select2-search input {
/*
Force border-box so that % widths fit the parent
container without overlap because of margin/padding.
More Info : http://www.quirksmode.org/css/box.html
*/
-webkit-box-sizing: border-box; /* webkit */
-moz-box-sizing: border-box; /* firefox */
box-sizing: border-box; /* css3 */
}
.select2-container .select2-choice {
display: block;
height: 26px;
padding: 0 0 0 8px;
overflow: hidden;
position: relative;
border: 1px solid #aaa;
white-space: nowrap;
line-height: 26px;
color: #444;
text-decoration: none;
border-radius: 4px;
background-clip: padding-box;
-webkit-touch-callout: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
background-color: #fff;
}
.select2-container.select2-drop-above .select2-choice {
border-bottom-color: #aaa;
border-radius: 0 0 4px 4px;
}
.select2-container.select2-allowclear .select2-choice .select2-chosen {
margin-right: 42px;
}
.select2-container .select2-choice > .select2-chosen {
margin-right: 26px;
display: block;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
float: none;
width: auto;
}
.select2-container .select2-choice abbr {
display: none;
width: 12px;
height: 12px;
position: absolute;
right: 24px;
top: 8px;
font-size: 1px;
text-decoration: none;
border: 0;
background: asset-url('select2.png') right top no-repeat;
cursor: pointer;
outline: 0;
}
.select2-container.select2-allowclear .select2-choice abbr {
display: inline-block;
}
.select2-container .select2-choice abbr:hover {
background-position: right -11px;
cursor: pointer;
}
.select2-drop-mask {
border: 0;
margin: 0;
padding: 0;
position: fixed;
left: 0;
top: 0;
min-height: 100%;
min-width: 100%;
height: auto;
width: auto;
opacity: 0;
z-index: 9998;
/* styles required for IE to work */
background-color: #fff;
filter: alpha(opacity=0);
}
.select2-drop {
width: 100%;
margin-top: -1px;
position: absolute;
z-index: 9999;
top: 100%;
background: #fff;
color: #000;
border: 1px solid #aaa;
border-top: 0;
-webkit-box-shadow: 0 4px 5px rgba(0, 0, 0, .15);
box-shadow: 0 4px 5px rgba(0, 0, 0, .15);
}
.select2-drop.select2-drop-above {
margin-top: 1px;
border-top: 1px solid #aaa;
border-bottom: 0;
-webkit-box-shadow: 0 -4px 5px rgba(0, 0, 0, .15);
box-shadow: 0 -4px 5px rgba(0, 0, 0, .15);
}
.select2-drop-active {
border: 1px solid #5897fb;
border-top: none;
}
.select2-drop.select2-drop-above.select2-drop-active {
border-top: 1px solid #5897fb;
}
.select2-drop-auto-width {
border-top: 1px solid #aaa;
width: auto;
}
.select2-drop-auto-width .select2-search {
padding-top: 4px;
}
.select2-container .select2-choice .select2-arrow {
display: inline-block;
width: 18px;
height: 100%;
position: absolute;
right: 0;
top: 0;
border-radius: 0 4px 4px 0;
background-clip: padding-box;
}
.select2-container .select2-choice .select2-arrow b {
display: block;
width: 100%;
height: 100%;
background: asset-url('select2.png') no-repeat 0 1px;
}
.select2-search {
display: inline-block;
width: 100%;
min-height: 26px;
margin: 0;
padding-left: 4px;
padding-right: 4px;
position: relative;
z-index: 10000;
white-space: nowrap;
}
//noinspection CssOverwrittenProperties
.select2-search input {
width: 100%;
height: auto !important;
min-height: 26px;
padding: 4px 20px 4px 5px;
margin: 0;
outline: 0;
font-family: sans-serif;
font-size: 1em;
border: 1px solid #aaa;
border-radius: 0;
-webkit-box-shadow: none;
box-shadow: none;
background: #fff asset-url('select2.png') no-repeat 100% -22px;
background: asset-url('select2.png') no-repeat 100% -22px, -webkit-gradient(linear, left bottom, left top, color-stop(0.85, #fff), color-stop(0.99, #eee));
background: asset-url('select2.png') no-repeat 100% -22px, -webkit-linear-gradient(center bottom, #fff 85%, #eee 99%);
background: asset-url('select2.png') no-repeat 100% -22px, -moz-linear-gradient(center bottom, #fff 85%, #eee 99%);
background: asset-url('select2.png') no-repeat 100% -22px, linear-gradient(to bottom, #fff 85%, #eee 99%) 0 0;
}
.select2-drop.select2-drop-above .select2-search input {
margin-top: 4px;
}
//noinspection CssOverwrittenProperties
.select2-search input.select2-active {
background: #fff asset-url('select2-spinner.gif') no-repeat 100%;
background: asset-url('select2-spinner.gif') no-repeat 100%, -webkit-gradient(linear, left bottom, left top, color-stop(0.85, #fff), color-stop(0.99, #eee));
background: asset-url('select2-spinner.gif') no-repeat 100%, -webkit-linear-gradient(center bottom, #fff 85%, #eee 99%);
background: asset-url('select2-spinner.gif') no-repeat 100%, -moz-linear-gradient(center bottom, #fff 85%, #eee 99%);
background: asset-url('select2-spinner.gif') no-repeat 100%, linear-gradient(to bottom, #fff 85%, #eee 99%) 0 0;
}
.select2-container-active .select2-choice,
.select2-container-active .select2-choices {
border: 1px solid #5897fb;
outline: none;
-webkit-box-shadow: 0 0 5px rgba(0, 0, 0, .3);
box-shadow: 0 0 5px rgba(0, 0, 0, .3);
}
.select2-dropdown-open .select2-choice {
border-bottom-color: transparent;
-webkit-box-shadow: 0 1px 0 #fff inset;
box-shadow: 0 1px 0 #fff inset;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
background-color: #eee;
}
.select2-dropdown-open.select2-drop-above .select2-choice,
.select2-dropdown-open.select2-drop-above .select2-choices {
border: 1px solid #5897fb;
border-top-color: transparent;
}
.select2-dropdown-open .select2-choice .select2-arrow {
background: transparent;
border-left: none;
filter: none;
}
.select2-dropdown-open .select2-choice .select2-arrow b {
background-position: -18px 1px;
}
.select2-hidden-accessible {
border: 0;
clip: rect(0 0 0 0);
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
width: 1px;
}
/* results */
.select2-results {
max-height: 200px;
padding: 0 0 0 4px;
margin: 4px 4px 4px 0;
position: relative;
overflow-x: hidden;
overflow-y: auto;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
.select2-results ul.select2-result-sub {
margin: 0;
padding-left: 0;
}
.select2-results li {
list-style: none;
display: list-item;
background-image: none;
}
.select2-results li.select2-result-with-children > .select2-result-label {
font-weight: bold;
}
.select2-results .select2-result-label {
padding: 3px 7px 4px;
margin: 0;
cursor: pointer;
min-height: 1em;
-webkit-touch-callout: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.select2-results-dept-1 .select2-result-label { padding-left: 20px }
.select2-results-dept-2 .select2-result-label { padding-left: 40px }
.select2-results-dept-3 .select2-result-label { padding-left: 60px }
.select2-results-dept-4 .select2-result-label { padding-left: 80px }
.select2-results-dept-5 .select2-result-label { padding-left: 100px }
.select2-results-dept-6 .select2-result-label { padding-left: 110px }
.select2-results-dept-7 .select2-result-label { padding-left: 120px }
.select2-results li em {
background: #feffde;
font-style: normal;
}
.select2-results .select2-highlighted em {
background: transparent;
}
.select2-results .select2-highlighted ul {
background: #fff;
color: #000;
}
.select2-results .select2-no-results,
.select2-results .select2-searching,
.select2-results .select2-selection-limit {
background: #f4f4f4;
display: list-item;
padding-left: 5px;
}
/*
disabled look for disabled choices in the results dropdown
*/
.select2-results .select2-disabled.select2-highlighted {
color: #666;
background: #f4f4f4;
display: list-item;
cursor: default;
}
.select2-results .select2-disabled {
background: #f4f4f4;
display: list-item;
cursor: default;
}
.select2-results .select2-selected {
display: none;
}
.select2-more-results.select2-active {
background: #f4f4f4 asset-url('select2-spinner.gif') no-repeat 100%;
}
.select2-more-results {
background: #f4f4f4;
display: list-item;
}
/* disabled styles */
.select2-container.select2-container-disabled .select2-choice {
background: #f4f4f4 none;
border: 1px solid #ddd;
cursor: default;
}
.select2-container.select2-container-disabled .select2-choice .select2-arrow {
background: #f4f4f4 none;
border-left: 0;
}
.select2-container.select2-container-disabled .select2-choice abbr {
display: none;
}
/* multiselect */
.select2-container-multi .select2-choices {
height: auto !important;
margin: 0;
padding: 0 5px 0 0;
position: relative;
cursor: text;
overflow: hidden;
}
.select2-locked {
padding: 3px 5px 3px 5px !important;
}
.select2-container-multi .select2-choices {
min-height: 26px;
}
.select2-container-multi.select2-container-active .select2-choices {
border: 1px solid #5897fb;
outline: none;
-webkit-box-shadow: 0 0 5px rgba(0, 0, 0, .3);
box-shadow: 0 0 5px rgba(0, 0, 0, .3);
}
.select2-container-multi .select2-choices li {
float: left;
list-style: none;
}
html[dir="rtl"] .select2-container-multi .select2-choices li
{
float: right;
}
.select2-container-multi .select2-choices .select2-search-field {
margin: 0;
padding: 0;
white-space: nowrap;
}
.select2-container-multi .select2-choices .select2-search-field input {
padding-left: 0;
font-family: sans-serif;
font-size: 1em;
color: #666;
outline: 0;
border: 0;
margin-bottom: 0;
-webkit-box-shadow: none;
box-shadow: none;
background: transparent !important;
}
.select2-container-multi .select2-choices .select2-search-field input.select2-active {
background: #fff asset-url('select2-spinner.gif') no-repeat 100% !important;
}
.select2-default {
color: #999 !important;
}
.select2-container-multi .select2-choices .select2-search-choice {
padding: 0 0 0 12px;
margin: 0;
position: relative;
color: #333;
cursor: default;
border: 1px solid #aaaaaa;
border-radius: 3px;
-webkit-box-shadow: 0 0 2px #fff inset, 0 1px 0 rgba(0, 0, 0, 0.05);
box-shadow: 0 0 2px #fff inset, 0 1px 0 rgba(0, 0, 0, 0.05);
background-clip: padding-box;
-webkit-touch-callout: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
background-color: #e4e4e4;
}
html[dir="rtl"] .select2-container-multi .select2-choices .select2-search-choice
{
margin-left: 0;
margin-right: 5px;
}
.select2-container-multi .select2-choices .select2-search-choice .select2-chosen {
cursor: default;
}
.select2-container-multi .select2-choices .select2-search-choice-focus {
background: #d4d4d4;
}
.select2-search-choice-close {
display: block;
width: 12px;
height: 13px;
position: absolute;
right: 3px;
top: 8px;
font-size: 1px;
outline: none;
background: asset-url('select2.png') right top no-repeat;
}
html[dir="rtl"] .select2-search-choice-close {
right: auto;
left: 3px;
}
.select2-container-multi .select2-search-choice-close {
left: 3px;
}
.select2-container-multi .select2-choices .select2-search-choice .select2-search-choice-close:hover {
background-position: right -11px;
}
.select2-container-multi .select2-choices .select2-search-choice-focus .select2-search-choice-close {
background-position: right -11px;
}
/* disabled styles */
.select2-container-multi.select2-container-disabled .select2-choices {
background: #f4f4f4 none;
border: 1px solid #ddd;
cursor: default;
}
.select2-container-multi.select2-container-disabled .select2-choices .select2-search-choice {
padding: 3px 5px 3px 5px;
border: 1px solid #ddd;
background: #f4f4f4 none;
}
.select2-container-multi.select2-container-disabled .select2-choices .select2-search-choice .select2-search-choice-close { display: none;
background: none;
}
/* end multiselect */
.select2-result-selectable .select2-match,
.select2-result-unselectable .select2-match {
text-decoration: underline;
}
.select2-offscreen, .select2-offscreen:focus {
clip: rect(0 0 0 0) !important;
width: 1px !important;
height: 1px !important;
border: 0 !important;
margin: 0 !important;
padding: 0 !important;
overflow: hidden !important;
position: absolute !important;
outline: 0 !important;
left: 0 !important;
top: 0 !important;
}
.select2-display-none {
display: none;
}
.select2-measure-scrollbar {
position: absolute;
top: -10000px;
left: -10000px;
width: 100px;
height: 100px;
overflow: scroll;
}

View File

@ -1,6 +1,5 @@
@import "vendor/normalize";
@import "vendor/font_awesome/font-awesome";
@import "vendor/select2";
@import "vendor/sweetalert";
@import "common/foundation/colors";
@import "common/foundation/variables";
@ -63,9 +62,6 @@ body.wizard {
.select {
width: 400px;
}
.select2-results .select2-highlighted {
background: #ff9;
}
.wizard-canvas {
position: absolute;
@ -484,7 +480,6 @@ body.wizard {
.wizard-column { margin: auto !important; }
.wizard-step-contents { min-height: auto !important; }
.wizard-step-banner { width: 100% !important; margin-bottom: 1em !important; }
.select2-container { width: 100% !important; }
.wizard-step-footer { display: block !important; }
.wizard-progress { margin-bottom: 10px !important; }
.wizard-buttons { text-align: right !important; }

View File

@ -51,9 +51,3 @@
<%- else -%>
<p><%= raw(t 'finish_installation.register.no_emails') %></p>
<%- end %>
<script>
(function() {
$('select').select2({ width: '400px' });
})();
</script>

View File

@ -75,30 +75,6 @@ QUnit.test("open advanced search", assert => {
andThen(() => assert.ok(visible('.search-advanced .search-advanced-options'), '"search-advanced-options" is visible'));
});
// these tests are screwy with the runloop
// test("validate population of advanced search", assert => {
// visit("/search");
// fillIn('.search input.full-page-search', 'test user:admin #bug group:moderators badge:Reader tags:monkey in:likes in:private in:wiki in:bookmarks status:open after:2016-10-05 min_post_count:10');
// click('.search-advanced-btn');
//
// andThen(() => {
// assert.ok(exists('.search-advanced-options span:contains("admin")'), 'has "admin" pre-populated');
// assert.ok(exists('.search-advanced-options .badge-category:contains("bug")'), 'has "bug" pre-populated');
// //assert.ok(exists('.search-advanced-options span:contains("moderators")'), 'has "moderators" pre-populated');
// //assert.ok(exists('.search-advanced-options span:contains("Reader")'), 'has "Reader" pre-populated');
// assert.ok(exists('.search-advanced-options .tag-chooser .tag-monkey'), 'has "monkey" pre-populated');
// assert.ok(exists('.search-advanced-options .in-likes:checked'), 'has "I liked" pre-populated');
// assert.ok(exists('.search-advanced-options .in-private:checked'), 'has "are in my messages" pre-populated');
// assert.ok(exists('.search-advanced-options .in-wiki:checked'), 'has "are wiki" pre-populated');
// assert.ok(exists('.search-advanced-options .combobox .select2-choice .select2-chosen:contains("I\'ve bookmarked")'), 'has "I\'ve bookmarked" pre-populated');
// assert.ok(exists('.search-advanced-options .combobox .select2-choice .select2-chosen:contains("are open")'), 'has "are open" pre-populated');
// assert.ok(exists('.search-advanced-options .combobox .select2-choice .select2-chosen:contains("after")'), 'has "after" pre-populated');
// assert.equal(find('.search-advanced-options #search-post-date').val(), "2016-10-05", 'has "2016-10-05" pre-populated');
// assert.equal(find('.search-advanced-options #search-min-post-count').val(), "10", 'has "10" pre-populated');
// });
// });
QUnit.test("escape search term", (assert) => {
visit("/search");
fillIn('.search input.full-page-search', '@<script>prompt(1337)</script>gmail.com');

File diff suppressed because one or more lines are too long