Introduces select-kit
* renames `select-box-kit` into `select-kit` * introduces `single-select` and `multi-select` as base components * introduces {{search-advanced-category-chooser}} as a better component for selecting category in advanced search * improves events handling in select-kit * recreates color selection inputs using {{multi-select}} and a custom {{selected-color}} component * replaces category-selector by a component using select-kit and based on multi-select * improves positioning of wrapper * removes the need for offscreen, and instead use `select-kit-header` as a base focus point for all select-kit based components * introduces a formal plugin api for select-kit based components * introduces a formal pattern for loading and updating select-kit based components: ``` computeValue() computeContent() mutateValue() ```
This commit is contained in:
parent
edc4b30f82
commit
39f3dbd945
12
.eslintrc
12
.eslintrc
|
@ -42,12 +42,12 @@
|
||||||
"invisible":true,
|
"invisible":true,
|
||||||
"asyncRender":true,
|
"asyncRender":true,
|
||||||
"selectDropdown":true,
|
"selectDropdown":true,
|
||||||
"selectBox":true,
|
"selectKit":true,
|
||||||
"expandSelectBoxKit":true,
|
"expandSelectKit":true,
|
||||||
"collapseSelectBoxKit":true,
|
"collapseSelectKit":true,
|
||||||
"selectBoxKitSelectRow":true,
|
"selectKitSelectRow":true,
|
||||||
"selectBoxKitSelectNoneRow":true,
|
"selectKitSelectNoneRow":true,
|
||||||
"selectBoxKitFillInFilter":true,
|
"selectKitFillInFilter":true,
|
||||||
"asyncTestDiscourse":true,
|
"asyncTestDiscourse":true,
|
||||||
"fixture":true,
|
"fixture":true,
|
||||||
"find":true,
|
"find":true,
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
{{category-selector categories=selectedCategories blacklist=selectedCategories}}
|
{{category-selector categories=selectedCategories}}
|
||||||
<div class='desc'>{{{unbound setting.description}}}</div>
|
<div class='desc'>{{{unbound setting.description}}}</div>
|
||||||
{{setting-validation-message message=validationMessage}}
|
{{setting-validation-message message=validationMessage}}
|
||||||
|
|
|
@ -48,7 +48,7 @@
|
||||||
<div class='filters'>
|
<div class='filters'>
|
||||||
<div>
|
<div>
|
||||||
<label>{{d-icon 'circle' class='tracking'}}{{i18n 'admin.web_hooks.categories_filter'}}</label>
|
<label>{{d-icon 'circle' class='tracking'}}{{i18n 'admin.web_hooks.categories_filter'}}</label>
|
||||||
{{category-selector categories=model.categories blacklist=model.categories}}
|
{{category-selector categories=model.categories}}
|
||||||
<div class="instructions">{{i18n 'admin.web_hooks.categories_filter_instructions'}}</div>
|
<div class="instructions">{{i18n 'admin.web_hooks.categories_filter_instructions'}}</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
//= require ./ember-addons/ember-computed-decorators
|
//= require ./ember-addons/ember-computed-decorators
|
||||||
//= require ./ember-addons/fmt
|
//= require ./ember-addons/fmt
|
||||||
//= require_tree ./discourse-common
|
//= require_tree ./discourse-common
|
||||||
//= require_tree ./select-box-kit
|
//= require_tree ./select-kit
|
||||||
//= require ./discourse
|
//= require ./discourse
|
||||||
//= require ./deprecated
|
//= require ./deprecated
|
||||||
|
|
||||||
|
|
|
@ -42,7 +42,8 @@ export function renderIcon(renderType, id, params) {
|
||||||
let rendererForType = renderer[renderType];
|
let rendererForType = renderer[renderType];
|
||||||
|
|
||||||
if (rendererForType) {
|
if (rendererForType) {
|
||||||
let result = rendererForType(REPLACEMENTS[id] || id, params || {});
|
const icon = { id, replacementId: REPLACEMENTS[id] };
|
||||||
|
let result = rendererForType(icon, params || {});
|
||||||
if (result) {
|
if (result) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -68,8 +69,14 @@ export function registerIconRenderer(renderer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Support for font awesome icons
|
// Support for font awesome icons
|
||||||
function faClasses(id, params) {
|
function faClasses(icon, params) {
|
||||||
let classNames = `fa fa-${id} d-icon d-icon-${id}`;
|
let classNames;
|
||||||
|
if (typeof icon.replacementId !== "undefined") {
|
||||||
|
classNames = `fa fa-${icon.replacementId} d-icon ${icon.id}`;
|
||||||
|
} else {
|
||||||
|
classNames = `fa fa-${icon.id} d-icon d-${icon.id}`;
|
||||||
|
}
|
||||||
|
|
||||||
if (params) {
|
if (params) {
|
||||||
if (params.modifier) { classNames += " fa-" + params.modifier; }
|
if (params.modifier) { classNames += " fa-" + params.modifier; }
|
||||||
if (params['class']) { classNames += ' ' + params['class']; }
|
if (params['class']) { classNames += ' ' + params['class']; }
|
||||||
|
@ -81,9 +88,9 @@ function faClasses(id, params) {
|
||||||
registerIconRenderer({
|
registerIconRenderer({
|
||||||
name: 'font-awesome',
|
name: 'font-awesome',
|
||||||
|
|
||||||
string(id, params) {
|
string(icon, params) {
|
||||||
let tagName = params.tagName || 'i';
|
let tagName = params.tagName || 'i';
|
||||||
let html = `<${tagName} class='${faClasses(id, params)}'`;
|
let html = `<${tagName} class='${faClasses(icon, params)}'`;
|
||||||
if (params.title) { html += ` title='${I18n.t(params.title)}'`; }
|
if (params.title) { html += ` title='${I18n.t(params.title)}'`; }
|
||||||
if (params.label) { html += " aria-hidden='true'"; }
|
if (params.label) { html += " aria-hidden='true'"; }
|
||||||
html += `></${tagName}>`;
|
html += `></${tagName}>`;
|
||||||
|
@ -93,11 +100,11 @@ registerIconRenderer({
|
||||||
return html;
|
return html;
|
||||||
},
|
},
|
||||||
|
|
||||||
node(id, params) {
|
node(icon, params) {
|
||||||
let tagName = params.tagName || 'i';
|
let tagName = params.tagName || 'i';
|
||||||
|
|
||||||
const properties = {
|
const properties = {
|
||||||
className: faClasses(id, params),
|
className: faClasses(icon, params),
|
||||||
attributes: { "aria-hidden": true }
|
attributes: { "aria-hidden": true }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,49 +0,0 @@
|
||||||
import { categoryBadgeHTML } from 'discourse/helpers/category-link';
|
|
||||||
import Category from 'discourse/models/category';
|
|
||||||
import { on, observes } from 'ember-addons/ember-computed-decorators';
|
|
||||||
import { findRawTemplate } from 'discourse/lib/raw-templates';
|
|
||||||
|
|
||||||
export default Ember.Component.extend({
|
|
||||||
@observes('categories')
|
|
||||||
_update() {
|
|
||||||
if (this.get('canReceiveUpdates') === 'true')
|
|
||||||
this._initializeAutocomplete({updateData: true});
|
|
||||||
},
|
|
||||||
|
|
||||||
@on('didInsertElement')
|
|
||||||
_initializeAutocomplete(opts) {
|
|
||||||
const self = this,
|
|
||||||
regexp = new RegExp(`href=['\"]${Discourse.getURL('/c/')}([^'\"]+)`);
|
|
||||||
|
|
||||||
this.$('input').autocomplete({
|
|
||||||
items: this.get('categories'),
|
|
||||||
single: this.get('single'),
|
|
||||||
allowAny: false,
|
|
||||||
updateData: (opts && opts.updateData) ? opts.updateData : false,
|
|
||||||
dataSource(term) {
|
|
||||||
return Category.list().filter(category => {
|
|
||||||
const regex = new RegExp(term, 'i');
|
|
||||||
return category.get('name').match(regex) &&
|
|
||||||
!_.contains(self.get('blacklist') || [], category) &&
|
|
||||||
!_.contains(self.get('categories'), category) ;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
onChangeItems(items) {
|
|
||||||
const categories = _.map(items, link => {
|
|
||||||
const slug = link.match(regexp)[1];
|
|
||||||
return Category.findSingleBySlug(slug);
|
|
||||||
});
|
|
||||||
Em.run.next(() => {
|
|
||||||
let existingCategory = _.isArray(self.get('categories')) ? self.get('categories') : [self.get('categories')];
|
|
||||||
const result = _.intersection(existingCategory.map(itm => itm.id), categories.map(itm => itm.id));
|
|
||||||
if (result.length !== categories.length || existingCategory.length !== categories.length)
|
|
||||||
self.set('categories', categories);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
template: findRawTemplate('category-selector-autocomplete'),
|
|
||||||
transformComplete(category) {
|
|
||||||
return categoryBadgeHTML(category, {allowUncategorized: true});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { default as computed, observes } from "ember-addons/ember-computed-decorators";
|
import { default as computed, observes } from "ember-addons/ember-computed-decorators";
|
||||||
import {
|
import {
|
||||||
FORMAT,
|
FORMAT,
|
||||||
} from "select-box-kit/components/future-date-input-selector";
|
} from "select-kit/components/future-date-input-selector";
|
||||||
|
|
||||||
import { PUBLISH_TO_CATEGORY_STATUS_TYPE } from 'discourse/controllers/edit-topic-timer';
|
import { PUBLISH_TO_CATEGORY_STATUS_TYPE } from 'discourse/controllers/edit-topic-timer';
|
||||||
|
|
||||||
|
|
|
@ -185,18 +185,18 @@ export default Em.Component.extend({
|
||||||
const userInput = Discourse.Category.findBySlug(subcategories[1], subcategories[0]);
|
const userInput = Discourse.Category.findBySlug(subcategories[1], subcategories[0]);
|
||||||
if ((!existingInput && userInput)
|
if ((!existingInput && userInput)
|
||||||
|| (existingInput && userInput && existingInput.id !== userInput.id))
|
|| (existingInput && userInput && existingInput.id !== userInput.id))
|
||||||
this.set('searchedTerms.category', [userInput]);
|
this.set('searchedTerms.category', userInput);
|
||||||
} else
|
} else
|
||||||
if (isNaN(subcategories)) {
|
if (isNaN(subcategories)) {
|
||||||
const userInput = Discourse.Category.findSingleBySlug(subcategories[0]);
|
const userInput = Discourse.Category.findSingleBySlug(subcategories[0]);
|
||||||
if ((!existingInput && userInput)
|
if ((!existingInput && userInput)
|
||||||
|| (existingInput && userInput && existingInput.id !== userInput.id))
|
|| (existingInput && userInput && existingInput.id !== userInput.id))
|
||||||
this.set('searchedTerms.category', [userInput]);
|
this.set('searchedTerms.category', userInput);
|
||||||
} else {
|
} else {
|
||||||
const userInput = Discourse.Category.findById(subcategories[0]);
|
const userInput = Discourse.Category.findById(subcategories[0]);
|
||||||
if ((!existingInput && userInput)
|
if ((!existingInput && userInput)
|
||||||
|| (existingInput && userInput && existingInput.id !== userInput.id))
|
|| (existingInput && userInput && existingInput.id !== userInput.id))
|
||||||
this.set('searchedTerms.category', [userInput]);
|
this.set('searchedTerms.category', userInput);
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
this.set('searchedTerms.category', '');
|
this.set('searchedTerms.category', '');
|
||||||
|
@ -303,11 +303,11 @@ export default Em.Component.extend({
|
||||||
|
|
||||||
const slugCategoryMatches = (match.length !== 0) ? match[0].match(REGEXP_CATEGORY_SLUG) : null;
|
const slugCategoryMatches = (match.length !== 0) ? match[0].match(REGEXP_CATEGORY_SLUG) : null;
|
||||||
const idCategoryMatches = (match.length !== 0) ? match[0].match(REGEXP_CATEGORY_ID) : null;
|
const idCategoryMatches = (match.length !== 0) ? match[0].match(REGEXP_CATEGORY_ID) : null;
|
||||||
if (categoryFilter && categoryFilter[0]) {
|
if (categoryFilter) {
|
||||||
const id = categoryFilter[0].id;
|
const id = categoryFilter.id;
|
||||||
const slug = categoryFilter[0].slug;
|
const slug = categoryFilter.slug;
|
||||||
if (categoryFilter[0].parentCategory) {
|
if (categoryFilter.parentCategory) {
|
||||||
const parentSlug = categoryFilter[0].parentCategory.slug;
|
const parentSlug = categoryFilter.parentCategory.slug;
|
||||||
if (slugCategoryMatches)
|
if (slugCategoryMatches)
|
||||||
searchTerm = searchTerm.replace(slugCategoryMatches[0], `#${parentSlug}:${slug}`);
|
searchTerm = searchTerm.replace(slugCategoryMatches[0], `#${parentSlug}:${slug}`);
|
||||||
else if (idCategoryMatches)
|
else if (idCategoryMatches)
|
||||||
|
|
|
@ -12,6 +12,7 @@ export default MountWidget.extend(Docking, {
|
||||||
buildArgs() {
|
buildArgs() {
|
||||||
let attrs = {
|
let attrs = {
|
||||||
topic: this.get('topic'),
|
topic: this.get('topic'),
|
||||||
|
notificationLevel: this.get('notificationLevel'),
|
||||||
topicTrackingState: this.topicTrackingState,
|
topicTrackingState: this.topicTrackingState,
|
||||||
enteredIndex: this.get('enteredIndex'),
|
enteredIndex: this.get('enteredIndex'),
|
||||||
dockAt: this.dockAt,
|
dockAt: this.dockAt,
|
||||||
|
|
|
@ -21,6 +21,7 @@ import { attachAdditionalPanel } from 'discourse/widgets/header';
|
||||||
import { registerIconRenderer, replaceIcon } from 'discourse-common/lib/icon-library';
|
import { registerIconRenderer, replaceIcon } from 'discourse-common/lib/icon-library';
|
||||||
import { addNavItem } from 'discourse/models/nav-item';
|
import { addNavItem } from 'discourse/models/nav-item';
|
||||||
import { replaceFormatter } from 'discourse/lib/utilities';
|
import { replaceFormatter } from 'discourse/lib/utilities';
|
||||||
|
import { modifySelectKit } from "select-kit/mixins/plugin-api";
|
||||||
|
|
||||||
// If you add any methods to the API ensure you bump up this number
|
// If you add any methods to the API ensure you bump up this number
|
||||||
const PLUGIN_API_VERSION = '0.8.12';
|
const PLUGIN_API_VERSION = '0.8.12';
|
||||||
|
@ -589,6 +590,21 @@ class PluginApi {
|
||||||
formatUsername(fn) {
|
formatUsername(fn) {
|
||||||
replaceFormatter(fn);
|
replaceFormatter(fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Access SelectKit plugin api
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
*
|
||||||
|
* modifySelectKit("topic-footer-mobile-dropdown").appendContent(() => [{
|
||||||
|
* name: "discourse",
|
||||||
|
* id: 1
|
||||||
|
* }])
|
||||||
|
*/
|
||||||
|
modifySelectKit(pluginApiKey) {
|
||||||
|
return modifySelectKit(pluginApiKey);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let _pluginv01;
|
let _pluginv01;
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
<input class='category-selector' type='text' name='categories'>
|
|
|
@ -9,7 +9,7 @@
|
||||||
{{navigation-bar navItems=navItems filterMode=filterMode category=category}}
|
{{navigation-bar navItems=navItems filterMode=filterMode category=category}}
|
||||||
|
|
||||||
{{#if showCategoryNotifications}}
|
{{#if showCategoryNotifications}}
|
||||||
{{category-notifications-button category=category}}
|
{{category-notifications-button value=category.notification_level category=category}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
{{create-topic-button
|
{{create-topic-button
|
||||||
|
|
|
@ -22,7 +22,9 @@
|
||||||
{{category-chooser
|
{{category-chooser
|
||||||
none="category.none"
|
none="category.none"
|
||||||
value=category.parent_category_id
|
value=category.parent_category_id
|
||||||
|
excludeCategoryId=category.id
|
||||||
categories=parentCategories
|
categories=parentCategories
|
||||||
|
allowSubCategories=false
|
||||||
allowUncategorized=false}}
|
allowUncategorized=false}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</section>
|
</section>
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
<div class="control-group pull-left">
|
<div class="control-group pull-left">
|
||||||
<label class="control-label" for="search-in-category">{{i18n "search.advanced.in_category.label"}}</label>
|
<label class="control-label" for="search-in-category">{{i18n "search.advanced.in_category.label"}}</label>
|
||||||
<div class="controls">
|
<div class="controls">
|
||||||
{{category-selector categories=searchedTerms.category single="true" canReceiveUpdates="true"}}
|
{{search-advanced-category-chooser value=searchedTerms.category}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -74,10 +74,10 @@
|
||||||
args=(hash topic=topic)
|
args=(hash topic=topic)
|
||||||
connectorTagName="span"}}
|
connectorTagName="span"}}
|
||||||
|
|
||||||
{{pinned-button topic=topic}}
|
{{pinned-button pinned=topic.pinned topic=topic}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{topic-notifications-button topic=topic}}
|
{{topic-notifications-button notificationLevel=topic.details.notification_level topic=topic}}
|
||||||
|
|
||||||
{{plugin-outlet name="after-topic-footer-buttons"
|
{{plugin-outlet name="after-topic-footer-buttons"
|
||||||
args=(hash topic=topic)
|
args=(hash topic=topic)
|
||||||
|
|
|
@ -85,6 +85,7 @@
|
||||||
|
|
||||||
{{topic-timeline
|
{{topic-timeline
|
||||||
topic=model
|
topic=model
|
||||||
|
notificationLevel=model.details.notification_level
|
||||||
prevEvent=info.prevEvent
|
prevEvent=info.prevEvent
|
||||||
fullscreen=info.topicProgressExpanded
|
fullscreen=info.topicProgressExpanded
|
||||||
enteredIndex=enteredIndex
|
enteredIndex=enteredIndex
|
||||||
|
|
|
@ -8,6 +8,6 @@
|
||||||
{{i18n "topic.unsubscribe.change_notification_state"}}
|
{{i18n "topic.unsubscribe.change_notification_state"}}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
{{topic-notifications-button topic=model}}
|
{{topic-notifications-button notificationLevel=model.details.notification_level topic=model}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -73,7 +73,7 @@
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
{{#if isGroup}}
|
{{#if isGroup}}
|
||||||
{{group-notifications-button group=group user=model}}
|
{{group-notifications-button value=group.group_user.notification_level group=group user=model}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
export default class ComponentConnector {
|
export default class ComponentConnector {
|
||||||
constructor(widget, componentName, opts) {
|
constructor(widget, componentName, opts, trackedProperties) {
|
||||||
this.widget = widget;
|
this.widget = widget;
|
||||||
this.opts = opts;
|
this.opts = opts;
|
||||||
this.componentName = componentName;
|
this.componentName = componentName;
|
||||||
|
this.trackedProperties = trackedProperties || [];
|
||||||
}
|
}
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
const $elem = $('<div style="display: inline-block;" class="widget-component-connector"></div>');
|
const $elem = $('<div style="display: inline-flex;" class="widget-component-connector"></div>');
|
||||||
const elem = $elem[0];
|
const elem = $elem[0];
|
||||||
const { opts, widget, componentName } = this;
|
const { opts, widget, componentName } = this;
|
||||||
|
|
||||||
|
@ -29,7 +30,18 @@ export default class ComponentConnector {
|
||||||
return elem;
|
return elem;
|
||||||
}
|
}
|
||||||
|
|
||||||
update() { }
|
update(prev) {
|
||||||
|
let shouldInit = false;
|
||||||
|
this.trackedProperties.forEach(prop => {
|
||||||
|
if (prev.opts[prop] !== this.opts[prop]) {
|
||||||
|
shouldInit = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (shouldInit === true) return this.init();
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ComponentConnector.prototype.type = 'Widget';
|
ComponentConnector.prototype.type = 'Widget';
|
||||||
|
|
|
@ -291,7 +291,7 @@ createWidget('timeline-footer-controls', {
|
||||||
|
|
||||||
html(attrs) {
|
html(attrs) {
|
||||||
const controls = [];
|
const controls = [];
|
||||||
const { currentUser, fullScreen, topic } = attrs;
|
const { currentUser, fullScreen, topic, notificationLevel } = attrs;
|
||||||
|
|
||||||
if (currentUser && !fullScreen) {
|
if (currentUser && !fullScreen) {
|
||||||
if (topic.get('details.can_create_post')) {
|
if (topic.get('details.can_create_post')) {
|
||||||
|
@ -315,12 +315,13 @@ createWidget('timeline-footer-controls', {
|
||||||
|
|
||||||
if (currentUser) {
|
if (currentUser) {
|
||||||
controls.push(new ComponentConnector(this,
|
controls.push(new ComponentConnector(this,
|
||||||
'topic-notifications-button',
|
'topic-notifications-options',
|
||||||
{
|
{
|
||||||
|
value: notificationLevel,
|
||||||
topic,
|
topic,
|
||||||
appendReason: false,
|
|
||||||
showFullTitle: false
|
showFullTitle: false
|
||||||
}
|
},
|
||||||
|
["value"]
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,45 +0,0 @@
|
||||||
import MultiComboBoxComponent from "select-box-kit/components/multi-combo-box";
|
|
||||||
|
|
||||||
export default MultiComboBoxComponent.extend({
|
|
||||||
classNames: "admin-group-selector",
|
|
||||||
selected: null,
|
|
||||||
available: null,
|
|
||||||
allowAny: false,
|
|
||||||
|
|
||||||
didReceiveAttrs() {
|
|
||||||
this._super();
|
|
||||||
|
|
||||||
this.set("value", this.get("selected").map(s => this._valueForContent(s)));
|
|
||||||
this.set("content", this.get("available"));
|
|
||||||
},
|
|
||||||
|
|
||||||
formatRowContent(content) {
|
|
||||||
let formatedContent = this._super(content);
|
|
||||||
formatedContent.locked = content.automatic;
|
|
||||||
return formatedContent;
|
|
||||||
},
|
|
||||||
|
|
||||||
didUpdateAttrs() {
|
|
||||||
this._super();
|
|
||||||
|
|
||||||
this.set("highlightedValue", null);
|
|
||||||
Ember.run.schedule("afterRender", () => {
|
|
||||||
this.autoHighlightFunction();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
selectValuesFunction(values) {
|
|
||||||
values.forEach(value => {
|
|
||||||
this.triggerAction({
|
|
||||||
action: "groupAdded",
|
|
||||||
actionContext: this.get("content").findBy("id", parseInt(value, 10))
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
deselectValuesFunction(values) {
|
|
||||||
values.forEach(value => {
|
|
||||||
this.triggerAction({ action: "groupRemoved", actionContext: value });
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -1,131 +0,0 @@
|
||||||
import ComboBoxComponent from "select-box-kit/components/combo-box";
|
|
||||||
import { categoryBadgeHTML } from "discourse/helpers/category-link";
|
|
||||||
import { on } from "ember-addons/ember-computed-decorators";
|
|
||||||
import computed from "ember-addons/ember-computed-decorators";
|
|
||||||
import PermissionType from "discourse/models/permission-type";
|
|
||||||
import Category from "discourse/models/category";
|
|
||||||
const { get, isNone, isEmpty } = Ember;
|
|
||||||
|
|
||||||
export default ComboBoxComponent.extend({
|
|
||||||
classNames: "category-chooser",
|
|
||||||
filterable: true,
|
|
||||||
castInteger: true,
|
|
||||||
allowUncategorized: null,
|
|
||||||
|
|
||||||
filteredContentFunction(computedContent, computedValue, filter) {
|
|
||||||
if (isEmpty(filter)) { return computedContent; }
|
|
||||||
|
|
||||||
const _matchFunction = (f, text) => {
|
|
||||||
return text.toLowerCase().indexOf(f) > -1;
|
|
||||||
};
|
|
||||||
const lowerFilter = filter.toLowerCase();
|
|
||||||
|
|
||||||
return computedContent.filter(c => {
|
|
||||||
const category = Category.findById(get(c, "value"));
|
|
||||||
const text = get(c, "name");
|
|
||||||
if (category && category.get("parentCategory")) {
|
|
||||||
const categoryName = category.get("parentCategory.name");
|
|
||||||
return _matchFunction(lowerFilter, text) || _matchFunction(lowerFilter, categoryName);
|
|
||||||
} else {
|
|
||||||
return _matchFunction(lowerFilter, text);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
@computed("rootNone", "rootNoneLabel")
|
|
||||||
none(rootNone, rootNoneLabel) {
|
|
||||||
if (this.siteSettings.allow_uncategorized_topics || this.get("allowUncategorized")) {
|
|
||||||
if (!isNone(rootNone)) {
|
|
||||||
return rootNoneLabel || "category.none";
|
|
||||||
} else {
|
|
||||||
return Category.findUncategorized();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return "category.choose";
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
@computed
|
|
||||||
templateForRow() {
|
|
||||||
return rowComponent => this._rowContentTemplate(rowComponent.get("content"));
|
|
||||||
},
|
|
||||||
|
|
||||||
@computed
|
|
||||||
templateForNoneRow() {
|
|
||||||
return rowComponent => this._rowContentTemplate(rowComponent.get("content"));
|
|
||||||
},
|
|
||||||
|
|
||||||
@computed("scopedCategoryId", "content.[]")
|
|
||||||
computedContent(scopedCategoryId, categories) {
|
|
||||||
// Always scope to the parent of a category, if present
|
|
||||||
if (scopedCategoryId) {
|
|
||||||
const scopedCat = Category.findById(scopedCategoryId);
|
|
||||||
scopedCategoryId = scopedCat.get("parent_category_id") || scopedCat.get("id");
|
|
||||||
}
|
|
||||||
|
|
||||||
const excludeCategoryId = this.get("excludeCategoryId");
|
|
||||||
|
|
||||||
return categories.filter(c => {
|
|
||||||
const categoryId = get(c, "value");
|
|
||||||
if (scopedCategoryId && categoryId !== scopedCategoryId && get(c, "originalContent.parent_category_id") !== scopedCategoryId) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (get(c, 'originalContent.isUncategorizedCategory') || excludeCategoryId === categoryId) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return get(c, 'originalContent.permission') === PermissionType.FULL;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
@on("didRender")
|
|
||||||
_bindComposerResizing() {
|
|
||||||
this.appEvents.on("composer:resized", this, this.applyDirection);
|
|
||||||
},
|
|
||||||
|
|
||||||
@on("willDestroyElement")
|
|
||||||
_unbindComposerResizing() {
|
|
||||||
this.appEvents.off("composer:resized");
|
|
||||||
},
|
|
||||||
|
|
||||||
@computed("site.sortedCategories")
|
|
||||||
content() {
|
|
||||||
const categories = Discourse.SiteSettings.fixed_category_positions_on_create ?
|
|
||||||
Category.list() :
|
|
||||||
Category.listByActivity();
|
|
||||||
return this.formatContents(categories);
|
|
||||||
},
|
|
||||||
|
|
||||||
_rowContentTemplate(content) {
|
|
||||||
let category;
|
|
||||||
|
|
||||||
// If we have no id, but text with the uncategorized name, we can use that badge.
|
|
||||||
if (isEmpty(get(content, "value"))) {
|
|
||||||
const uncat = Category.findUncategorized();
|
|
||||||
if (uncat && uncat.get("name") === get(content, "name")) {
|
|
||||||
category = uncat;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
category = Category.findById(parseInt(get(content, "value"), 10));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!category) return get(content, "name");
|
|
||||||
let result = categoryBadgeHTML(category, {link: false, allowUncategorized: true, hideParent: true});
|
|
||||||
const parentCategoryId = category.get("parent_category_id");
|
|
||||||
|
|
||||||
if (parentCategoryId) {
|
|
||||||
result = `<div class="category-status">${categoryBadgeHTML(Category.findById(parentCategoryId), {link: false})} ${result}`;
|
|
||||||
} else {
|
|
||||||
result = `<div class="category-status">${result}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
result += ` <span class="topic-count">× ${category.get("topic_count")}</span></div>`;
|
|
||||||
|
|
||||||
const description = category.get("description");
|
|
||||||
// TODO wtf how can this be null?;
|
|
||||||
if (description && description !== "null") {
|
|
||||||
result += `<div class="category-desc">${description.substr(0, 200)}${description.length > 200 ? '…' : ''}</div>`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -1,13 +0,0 @@
|
||||||
import NotificationOptionsComponent from "select-box-kit/components/notifications-button";
|
|
||||||
|
|
||||||
export default NotificationOptionsComponent.extend({
|
|
||||||
classNames: "category-notifications-button",
|
|
||||||
isHidden: Ember.computed.or("category.deleted", "site.isMobileDevice"),
|
|
||||||
i18nPrefix: "category.notifications",
|
|
||||||
value: Ember.computed.alias("category.notification_level"),
|
|
||||||
headerComponent: "category-notifications-button/category-notifications-button-header",
|
|
||||||
|
|
||||||
selectValueFunction(value) {
|
|
||||||
this.get("category").setNotification(value);
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -1,13 +0,0 @@
|
||||||
import NotificationButtonHeader from "select-box-kit/components/notifications-button/notifications-button-header";
|
|
||||||
import computed from "ember-addons/ember-computed-decorators";
|
|
||||||
import { iconHTML } from 'discourse-common/lib/icon-library';
|
|
||||||
|
|
||||||
export default NotificationButtonHeader.extend({
|
|
||||||
classNames: "category-notifications-button-header",
|
|
||||||
shouldDisplaySelectedName: false,
|
|
||||||
|
|
||||||
@computed("_selectedDetails.icon", "_selectedDetails.key")
|
|
||||||
icon() {
|
|
||||||
return `${this._super()}${iconHTML("caret-down")}`.htmlSafe();
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -1,39 +0,0 @@
|
||||||
import SelectBoxKitHeaderComponent from "select-box-kit/components/select-box-kit/select-box-kit-header";
|
|
||||||
import { default as computed } from "ember-addons/ember-computed-decorators";
|
|
||||||
|
|
||||||
export default SelectBoxKitHeaderComponent.extend({
|
|
||||||
layoutName: "select-box-kit/templates/components/combo-box/combo-box-header",
|
|
||||||
classNames: "combo-box-header",
|
|
||||||
|
|
||||||
clearable: Ember.computed.alias("options.clearable"),
|
|
||||||
caretUpIcon: Ember.computed.alias("options.caretUpIcon"),
|
|
||||||
caretDownIcon: Ember.computed.alias("options.caretDownIcon"),
|
|
||||||
selectedName: Ember.computed.alias("options.selectedName"),
|
|
||||||
|
|
||||||
@computed("isExpanded", "caretUpIcon", "caretDownIcon")
|
|
||||||
caretIcon(isExpanded, caretUpIcon, caretDownIcon) {
|
|
||||||
return isExpanded === true ? caretUpIcon : caretDownIcon;
|
|
||||||
},
|
|
||||||
|
|
||||||
@computed("clearable", "selectedContent")
|
|
||||||
shouldDisplayClearableButton(clearable, selectedContent) {
|
|
||||||
return clearable === true && !Ember.isEmpty(selectedContent);
|
|
||||||
},
|
|
||||||
|
|
||||||
@computed("options.selectedName", "selectedContent.firstObject.name", "none.name")
|
|
||||||
selectedName(selectedName, name, noneName) {
|
|
||||||
if (Ember.isPresent(selectedName)) {
|
|
||||||
return selectedName;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Ember.isNone(name)) {
|
|
||||||
if (Ember.isNone(noneName)) {
|
|
||||||
return this._super();
|
|
||||||
} else {
|
|
||||||
return noneName;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -1,22 +0,0 @@
|
||||||
import SelectBoxKitComponent from "select-box-kit/components/select-box-kit";
|
|
||||||
|
|
||||||
export default SelectBoxKitComponent.extend({
|
|
||||||
classNames: "dropdown-select-box",
|
|
||||||
verticalOffset: 3,
|
|
||||||
fullWidthOnMobile: true,
|
|
||||||
filterable: false,
|
|
||||||
autoFilterable: false,
|
|
||||||
headerComponent: "dropdown-select-box/dropdown-select-box-header",
|
|
||||||
rowComponent: "dropdown-select-box/dropdown-select-box-row",
|
|
||||||
|
|
||||||
clickOutside() {
|
|
||||||
if (this.get("isExpanded") === false) { return; }
|
|
||||||
this.close();
|
|
||||||
},
|
|
||||||
|
|
||||||
didSelectValue() {
|
|
||||||
this._super();
|
|
||||||
|
|
||||||
this.blur();
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -1,6 +0,0 @@
|
||||||
import SelectBoxKitHeaderComponent from "select-box-kit/components/select-box-kit/select-box-kit-header";
|
|
||||||
|
|
||||||
export default SelectBoxKitHeaderComponent.extend({
|
|
||||||
layoutName: "select-box-kit/templates/components/dropdown-select-box/dropdown-select-box-header",
|
|
||||||
classNames: "dropdown-select-box-header",
|
|
||||||
});
|
|
|
@ -1,9 +0,0 @@
|
||||||
import SelectBoxKitRowComponent from "select-box-kit/components/select-box-kit/select-box-kit-row";
|
|
||||||
|
|
||||||
export default SelectBoxKitRowComponent.extend({
|
|
||||||
layoutName: "select-box-kit/templates/components/dropdown-select-box/dropdown-select-box-row",
|
|
||||||
classNames: "dropdown-select-box-row",
|
|
||||||
|
|
||||||
name: Ember.computed.alias("content.name"),
|
|
||||||
description: Ember.computed.alias("content.originalContent.description")
|
|
||||||
});
|
|
|
@ -1,14 +0,0 @@
|
||||||
import ComboBoxHeaderComponent from "select-box-kit/components/combo-box/combo-box-header";
|
|
||||||
import DatetimeMixin from "select-box-kit/components/future-date-input-selector/mixin";
|
|
||||||
import computed from "ember-addons/ember-computed-decorators";
|
|
||||||
|
|
||||||
export default ComboBoxHeaderComponent.extend(DatetimeMixin, {
|
|
||||||
layoutName: "select-box-kit/templates/components/future-date-input-selector/future-date-input-selector-header",
|
|
||||||
classNames: "future-date-input-selector-header",
|
|
||||||
|
|
||||||
@computed("selectedContent.firstObject.value")
|
|
||||||
datetime(value) { return this._computeDatetimeForValue(value); },
|
|
||||||
|
|
||||||
@computed("selectedContent.firstObject.value")
|
|
||||||
icon(value) { return this._computeIconForValue(value); }
|
|
||||||
});
|
|
|
@ -1,14 +0,0 @@
|
||||||
import SelectBoxKitRowComponent from "select-box-kit/components/select-box-kit/select-box-kit-row";
|
|
||||||
import DatetimeMixin from "select-box-kit/components/future-date-input-selector/mixin";
|
|
||||||
import computed from "ember-addons/ember-computed-decorators";
|
|
||||||
|
|
||||||
export default SelectBoxKitRowComponent.extend(DatetimeMixin, {
|
|
||||||
layoutName: "select-box-kit/templates/components/future-date-input-selector/future-date-input-selector-row",
|
|
||||||
classNames: "future-date-input-selector-row",
|
|
||||||
|
|
||||||
@computed("content.value")
|
|
||||||
datetime(value) { return this._computeDatetimeForValue(value); },
|
|
||||||
|
|
||||||
@computed("content.value")
|
|
||||||
icon(value) { return this._computeIconForValue(value); }
|
|
||||||
});
|
|
|
@ -1,55 +0,0 @@
|
||||||
import MultiComboBoxComponent from "select-box-kit/components/multi-combo-box";
|
|
||||||
import { observes } from 'ember-addons/ember-computed-decorators';
|
|
||||||
|
|
||||||
export default MultiComboBoxComponent.extend({
|
|
||||||
classNames: "list-setting",
|
|
||||||
tokenSeparator: "|",
|
|
||||||
settingValue: "",
|
|
||||||
choices: null,
|
|
||||||
filterable: true,
|
|
||||||
|
|
||||||
init() {
|
|
||||||
const valuesFromString = this.get("settingValue").split(this.get("tokenSeparator"));
|
|
||||||
this.set("value", valuesFromString.reject(v => Ember.isEmpty(v)));
|
|
||||||
|
|
||||||
if (Ember.isNone(this.get("choices"))) {
|
|
||||||
this.set("content", valuesFromString);
|
|
||||||
} else {
|
|
||||||
this.set("content", this.get("choices"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Ember.isNone(this.get("settingName"))) {
|
|
||||||
this.set("nameProperty", this.get("settingName"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Ember.isEmpty(this.get("content"))) {
|
|
||||||
this.set("rowComponent", null);
|
|
||||||
this.set("noContentLabel", null);
|
|
||||||
}
|
|
||||||
|
|
||||||
this._super();
|
|
||||||
|
|
||||||
if (this.get("nameProperty").indexOf("color") > -1) {
|
|
||||||
this.set("headerComponentOptions", Ember.Object.create({
|
|
||||||
selectedNameComponent: "multi-combo-box/selected-color"
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
@observes("value.[]")
|
|
||||||
setSettingValue() {
|
|
||||||
this.set("settingValue", this.get("value").join(this.get("tokenSeparator")));
|
|
||||||
},
|
|
||||||
|
|
||||||
@observes("content.[]")
|
|
||||||
setChoices() { this.set("choices", this.get("content")); },
|
|
||||||
|
|
||||||
_handleTabOnKeyDown(event) {
|
|
||||||
if (this.$highlightedRow().length === 1) {
|
|
||||||
this._super(event);
|
|
||||||
} else {
|
|
||||||
this.close();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -1,240 +0,0 @@
|
||||||
import SelectBoxKitComponent from "select-box-kit/components/select-box-kit";
|
|
||||||
import computed from "ember-addons/ember-computed-decorators";
|
|
||||||
const { get, isNone, isEmpty } = Ember;
|
|
||||||
|
|
||||||
export default SelectBoxKitComponent.extend({
|
|
||||||
classNames: "multi-combo-box",
|
|
||||||
headerComponent: "multi-combo-box/multi-combo-box-header",
|
|
||||||
filterComponent: null,
|
|
||||||
headerText: "select_box.default_header_text",
|
|
||||||
allowAny: true,
|
|
||||||
allowValueMutation: false,
|
|
||||||
autoSelectFirst: false,
|
|
||||||
autoFilterable: true,
|
|
||||||
selectedNameComponent: "multi-combo-box/selected-name",
|
|
||||||
|
|
||||||
init() {
|
|
||||||
this._super();
|
|
||||||
|
|
||||||
if (isNone(this.get("value"))) { this.set("value", []); }
|
|
||||||
|
|
||||||
this.set("headerComponentOptions", Ember.Object.create({
|
|
||||||
selectedNameComponent: this.get("selectedNameComponent")
|
|
||||||
}));
|
|
||||||
},
|
|
||||||
|
|
||||||
@computed("filter")
|
|
||||||
templateForCreateRow() {
|
|
||||||
return (rowComponent) => {
|
|
||||||
return I18n.t("select_box.create", { content: rowComponent.get("content.name")});
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
keyDown(event) {
|
|
||||||
const keyCode = event.keyCode || event.which;
|
|
||||||
const $filterInput = this.$filterInput();
|
|
||||||
|
|
||||||
if (this.get("isFocused") === true && this.get("isExpanded") === false && keyCode === this.keys.BACKSPACE) {
|
|
||||||
this.expand();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// select all choices
|
|
||||||
if (event.metaKey === true && keyCode === 65 && isEmpty(this.get("filter"))) {
|
|
||||||
this.$(".choices .selected-name:not(.is-locked)").addClass("is-highlighted");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// clear selection when multiple
|
|
||||||
if (Ember.isEmpty(this.get("filter")) && this.$(".selected-name.is-highlighted").length >= 1 && keyCode === this.keys.BACKSPACE) {
|
|
||||||
const highlightedValues = [];
|
|
||||||
$.each(this.$(".selected-name.is-highlighted"), (i, el) => {
|
|
||||||
highlightedValues.push($(el).attr("data-value"));
|
|
||||||
});
|
|
||||||
|
|
||||||
this.send("onDeselect", highlightedValues);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// try to remove last item from the list
|
|
||||||
if (Ember.isEmpty(this.get("filter")) && keyCode === this.keys.BACKSPACE) {
|
|
||||||
let $lastSelectedValue = $(this.$(".choices .selected-name:not(.is-locked)").last());
|
|
||||||
|
|
||||||
if ($lastSelectedValue.length === 0) { return; }
|
|
||||||
|
|
||||||
if ($lastSelectedValue.hasClass("is-highlighted") || $(document.activeElement).is($lastSelectedValue)) {
|
|
||||||
this.send("onDeselect", this.get("selectedContent.lastObject.value"));
|
|
||||||
$filterInput.focus();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($filterInput.not(":visible") && $lastSelectedValue.length > 0) {
|
|
||||||
$lastSelectedValue.click();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($filterInput.val() === "") {
|
|
||||||
if ($filterInput.is(":focus")) {
|
|
||||||
if ($lastSelectedValue.length > 0) { $lastSelectedValue.click(); }
|
|
||||||
} else {
|
|
||||||
if ($lastSelectedValue.length > 0) {
|
|
||||||
$lastSelectedValue.click();
|
|
||||||
} else {
|
|
||||||
$filterInput.focus();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
@computed("value.[]")
|
|
||||||
computedValue(value) { return value.map(v => this._castInteger(v)); },
|
|
||||||
|
|
||||||
@computed("value.[]", "computedContent.[]")
|
|
||||||
selectedContent(value, computedContent) {
|
|
||||||
const contents = [];
|
|
||||||
value.forEach(v => {
|
|
||||||
const content = computedContent.findBy("value", v);
|
|
||||||
if (!isNone(content)) { contents.push(content); }
|
|
||||||
});
|
|
||||||
return contents;
|
|
||||||
},
|
|
||||||
|
|
||||||
filteredContentFunction(computedContent, computedValue, filter) {
|
|
||||||
computedContent = computedContent.filter(c => {
|
|
||||||
return !computedValue.includes(get(c, "value"));
|
|
||||||
});
|
|
||||||
|
|
||||||
if (isEmpty(filter)) { return computedContent; }
|
|
||||||
|
|
||||||
const lowerFilter = filter.toLowerCase();
|
|
||||||
return computedContent.filter(c => {
|
|
||||||
return get(c, "name").toLowerCase().indexOf(lowerFilter) > -1;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
willCreateContent() {
|
|
||||||
this.set("highlightedValue", null);
|
|
||||||
},
|
|
||||||
|
|
||||||
didCreateContent() {
|
|
||||||
this.clearFilter();
|
|
||||||
this.autoHighlightFunction();
|
|
||||||
},
|
|
||||||
|
|
||||||
createContentFunction(input) {
|
|
||||||
if (!this.get("content").includes(input)) {
|
|
||||||
this.get("content").pushObject(input);
|
|
||||||
this.get("value").pushObject(input);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
deselectValuesFunction(values) {
|
|
||||||
const contents = this._computeRemovableContentsForValues(values);
|
|
||||||
this.get("value").removeObjects(values);
|
|
||||||
this.get("content").removeObjects(contents);
|
|
||||||
},
|
|
||||||
|
|
||||||
highlightValueFunction(value) {
|
|
||||||
this.set("highlightedValue", value);
|
|
||||||
},
|
|
||||||
|
|
||||||
selectValuesFunction(values) {
|
|
||||||
this.get("value").pushObjects(values);
|
|
||||||
},
|
|
||||||
|
|
||||||
willSelectValues() {
|
|
||||||
this.expand();
|
|
||||||
this.set("highlightedValue", null);
|
|
||||||
},
|
|
||||||
|
|
||||||
didSelectValues() {
|
|
||||||
this.focus();
|
|
||||||
this.clearFilter();
|
|
||||||
this.autoHighlightFunction();
|
|
||||||
},
|
|
||||||
|
|
||||||
willDeselectValues() {
|
|
||||||
this.set("highlightedValue", null);
|
|
||||||
},
|
|
||||||
|
|
||||||
didDeselectValues() {
|
|
||||||
this.autoHighlightFunction();
|
|
||||||
},
|
|
||||||
|
|
||||||
willHighlightValue() {},
|
|
||||||
|
|
||||||
didHighlightValue() {},
|
|
||||||
|
|
||||||
autoHighlightFunction() {
|
|
||||||
Ember.run.schedule("afterRender", () => {
|
|
||||||
if (this.get("isExpanded") === false) { return; }
|
|
||||||
if (this.get("renderedBodyOnce") === false) { return; }
|
|
||||||
if (!isNone(this.get("highlightedValue"))) { return; }
|
|
||||||
|
|
||||||
if (isEmpty(this.get("filteredContent"))) {
|
|
||||||
if (!isEmpty(this.get("filter"))) {
|
|
||||||
this.send("onHighlight", this.get("filter"));
|
|
||||||
} else if (this.get("none") && !isEmpty(this.get("selectedContent"))) {
|
|
||||||
this.send("onHighlight", this.noneValue);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.send("onHighlight", this.get("filteredContent.firstObject.value"));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
actions: {
|
|
||||||
onClearSelection() {
|
|
||||||
const values = this.get("selectedContent").map(c => get(c, "value"));
|
|
||||||
this.send("onDeselect", values);
|
|
||||||
},
|
|
||||||
|
|
||||||
onHighlight(value) {
|
|
||||||
value = this._originalValueForValue(value);
|
|
||||||
this.willHighlightValue(value);
|
|
||||||
this.set("highlightedValue", value);
|
|
||||||
this.highlightValueFunction(value);
|
|
||||||
this.didHighlightValue(value);
|
|
||||||
},
|
|
||||||
|
|
||||||
onCreateContent(input) {
|
|
||||||
this.willCreateContent(input);
|
|
||||||
this.createContentFunction(input);
|
|
||||||
this.didCreateContent(input);
|
|
||||||
},
|
|
||||||
|
|
||||||
onSelect(values) {
|
|
||||||
values = Ember.makeArray(values).map(v => this._originalValueForValue(v));
|
|
||||||
this.willSelectValues(values);
|
|
||||||
this.selectValuesFunction(values);
|
|
||||||
this.didSelectValues(values);
|
|
||||||
},
|
|
||||||
|
|
||||||
onDeselect(values) {
|
|
||||||
values = Ember.makeArray(this._computeRemovableValues(values));
|
|
||||||
this.willDeselectValues(values);
|
|
||||||
this.deselectValuesFunction(values);
|
|
||||||
this.didSelectValues(values);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
_computeRemovableContentsForValues(values) {
|
|
||||||
const removableContents = [];
|
|
||||||
values.forEach(v => {
|
|
||||||
if (!this.get("_initialValues").includes(v)) {
|
|
||||||
const content = this._contentForValue(v);
|
|
||||||
if (!isNone(content)) { removableContents.push(content); }
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return removableContents;
|
|
||||||
},
|
|
||||||
|
|
||||||
_computeRemovableValues(values) {
|
|
||||||
return Ember.makeArray(values)
|
|
||||||
.map(v => this._originalValueForValue(v))
|
|
||||||
.filter(v => {
|
|
||||||
return get(this._computedContentForValue(v), "locked") !== true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -1,8 +0,0 @@
|
||||||
import SelectedNameComponent from "select-box-kit/components/multi-combo-box/selected-name";
|
|
||||||
|
|
||||||
export default SelectedNameComponent.extend({
|
|
||||||
didRender() {
|
|
||||||
const name = this.get("content.name");
|
|
||||||
this.$().css("border-bottom", Handlebars.Utils.escapeExpression(`7px solid #${name}`));
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -1,26 +0,0 @@
|
||||||
import DropdownSelectBoxHeaderComponent from "select-box-kit/components/dropdown-select-box/dropdown-select-box-header";
|
|
||||||
import computed from "ember-addons/ember-computed-decorators";
|
|
||||||
import { iconHTML } from 'discourse-common/lib/icon-library';
|
|
||||||
import { buttonDetails } from "discourse/lib/notification-levels";
|
|
||||||
|
|
||||||
export default DropdownSelectBoxHeaderComponent.extend({
|
|
||||||
classNames: "notifications-button-header",
|
|
||||||
|
|
||||||
i18nPrefix: Ember.computed.alias("options.i18nPrefix"),
|
|
||||||
shouldDisplaySelectedName: Ember.computed.alias("options.showFullTitle"),
|
|
||||||
|
|
||||||
@computed("_selectedDetails.icon", "_selectedDetails.key")
|
|
||||||
icon(icon, key) {
|
|
||||||
return iconHTML(icon, { class: key }).htmlSafe();
|
|
||||||
},
|
|
||||||
|
|
||||||
@computed("_selectedDetails.key", "i18nPrefix")
|
|
||||||
selectedName(key, prefix) {
|
|
||||||
return I18n.t(`${prefix}.${key}.title`);
|
|
||||||
},
|
|
||||||
|
|
||||||
@computed("selectedContent.firstObject.value")
|
|
||||||
_selectedDetails(value) {
|
|
||||||
return buttonDetails(value);
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -1,60 +0,0 @@
|
||||||
import DropdownSelectBoxComponent from "select-box-kit/components/dropdown-select-box";
|
|
||||||
import computed from "ember-addons/ember-computed-decorators";
|
|
||||||
import { observes } from "ember-addons/ember-computed-decorators";
|
|
||||||
import { on } from "ember-addons/ember-computed-decorators";
|
|
||||||
|
|
||||||
export default DropdownSelectBoxComponent.extend({
|
|
||||||
classNames: "pinned-options",
|
|
||||||
|
|
||||||
headerComponent: "pinned-options/pinned-options-header",
|
|
||||||
|
|
||||||
@on("didReceiveAttrs")
|
|
||||||
_setComponentOptions() {
|
|
||||||
this.set("headerComponentOptions", Ember.Object.create({
|
|
||||||
pinned: this.get("topic.pinned"),
|
|
||||||
pinnedGlobally: this.get("topic.pinned_globally")
|
|
||||||
}));
|
|
||||||
},
|
|
||||||
|
|
||||||
@computed("topic.pinned")
|
|
||||||
value(pinned) {
|
|
||||||
return pinned ? "pinned" : "unpinned";
|
|
||||||
},
|
|
||||||
|
|
||||||
@observes("topic.pinned")
|
|
||||||
_pinStateChanged() {
|
|
||||||
this.set("value", this.get("topic.pinned") ? "pinned" : "unpinned");
|
|
||||||
this._setComponentOptions();
|
|
||||||
},
|
|
||||||
|
|
||||||
@computed("topic.pinned_globally")
|
|
||||||
content(pinnedGlobally) {
|
|
||||||
const globally = pinnedGlobally ? "_globally" : "";
|
|
||||||
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
id: "pinned",
|
|
||||||
name: I18n.t("topic_statuses.pinned" + globally + ".title"),
|
|
||||||
description: I18n.t('topic_statuses.pinned' + globally + '.help'),
|
|
||||||
icon: "thumb-tack"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "unpinned",
|
|
||||||
name: I18n.t("topic_statuses.unpinned.title"),
|
|
||||||
icon: "thumb-tack",
|
|
||||||
description: I18n.t('topic_statuses.unpinned.help'),
|
|
||||||
iconClass: "unpinned"
|
|
||||||
}
|
|
||||||
];
|
|
||||||
},
|
|
||||||
|
|
||||||
selectValueFunction(value) {
|
|
||||||
const topic = this.get("topic");
|
|
||||||
|
|
||||||
if (value === "unpinned") {
|
|
||||||
topic.clearPin();
|
|
||||||
} else {
|
|
||||||
topic.rePin();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -1,30 +0,0 @@
|
||||||
import DropdownSelectBoxHeaderComponent from "select-box-kit/components/dropdown-select-box/dropdown-select-box-header";
|
|
||||||
import computed from "ember-addons/ember-computed-decorators";
|
|
||||||
import { iconHTML } from 'discourse-common/lib/icon-library';
|
|
||||||
|
|
||||||
export default DropdownSelectBoxHeaderComponent.extend({
|
|
||||||
classNames: "pinned-options-header",
|
|
||||||
|
|
||||||
pinnedGlobally: Ember.computed.alias("options.pinnedGlobally"),
|
|
||||||
pinned: Ember.computed.alias("options.pinned"),
|
|
||||||
|
|
||||||
@computed("pinned", "pinnedGlobally")
|
|
||||||
icon(pinned, pinnedGlobally) {
|
|
||||||
const globally = pinnedGlobally ? "_globally" : "";
|
|
||||||
const state = pinned ? `pinned${globally}` : "unpinned";
|
|
||||||
|
|
||||||
return iconHTML(
|
|
||||||
"thumb-tack",
|
|
||||||
{ class: (state === "unpinned" ? "unpinned" : null) }
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
@computed("pinned", "pinnedGlobally")
|
|
||||||
selectedName(pinned, pinnedGlobally) {
|
|
||||||
const globally = pinnedGlobally ? "_globally" : "";
|
|
||||||
const state = pinned ? `pinned${globally}` : "unpinned";
|
|
||||||
const title = I18n.t(`topic_statuses.${state}.title`);
|
|
||||||
|
|
||||||
return `${title}${iconHTML("caret-down")}`.htmlSafe();
|
|
||||||
},
|
|
||||||
});
|
|
|
@ -1,328 +0,0 @@
|
||||||
const { get, isNone, isEmpty, isPresent } = Ember;
|
|
||||||
import { on } from "ember-addons/ember-computed-decorators";
|
|
||||||
import computed from "ember-addons/ember-computed-decorators";
|
|
||||||
import UtilsMixin from "select-box-kit/mixins/utils";
|
|
||||||
import DomHelpersMixin from "select-box-kit/mixins/dom-helpers";
|
|
||||||
import KeyboardMixin from "select-box-kit/mixins/keyboard";
|
|
||||||
|
|
||||||
export default Ember.Component.extend(UtilsMixin, DomHelpersMixin, KeyboardMixin, {
|
|
||||||
layoutName: "select-box-kit/templates/components/select-box-kit",
|
|
||||||
classNames: "select-box-kit",
|
|
||||||
classNameBindings: [
|
|
||||||
"isFocused",
|
|
||||||
"isExpanded",
|
|
||||||
"isDisabled",
|
|
||||||
"isHidden",
|
|
||||||
"isAbove",
|
|
||||||
"isBelow",
|
|
||||||
"isLeftAligned",
|
|
||||||
"isRightAligned"
|
|
||||||
],
|
|
||||||
isDisabled: false,
|
|
||||||
isExpanded: false,
|
|
||||||
isFocused: false,
|
|
||||||
isHidden: false,
|
|
||||||
renderedBodyOnce: false,
|
|
||||||
renderedFilterOnce: false,
|
|
||||||
tabindex: 0,
|
|
||||||
scrollableParentSelector: ".modal-body",
|
|
||||||
value: null,
|
|
||||||
none: null,
|
|
||||||
highlightedValue: null,
|
|
||||||
noContentLabel: "select_box.no_content",
|
|
||||||
valueAttribute: "id",
|
|
||||||
nameProperty: "name",
|
|
||||||
autoFilterable: false,
|
|
||||||
filterable: false,
|
|
||||||
filter: "",
|
|
||||||
filterPlaceholder: "select_box.filter_placeholder",
|
|
||||||
filterIcon: "search",
|
|
||||||
rowComponent: "select-box-kit/select-box-kit-row",
|
|
||||||
rowComponentOptions: null,
|
|
||||||
noneRowComponent: "select-box-kit/select-box-kit-none-row",
|
|
||||||
createRowComponent: "select-box-kit/select-box-kit-create-row",
|
|
||||||
filterComponent: "select-box-kit/select-box-kit-filter",
|
|
||||||
headerComponent: "select-box-kit/select-box-kit-header",
|
|
||||||
headerComponentOptions: null,
|
|
||||||
collectionComponent: "select-box-kit/select-box-kit-collection",
|
|
||||||
collectionHeight: 200,
|
|
||||||
verticalOffset: 0,
|
|
||||||
horizontalOffset: 0,
|
|
||||||
fullWidthOnMobile: false,
|
|
||||||
castInteger: false,
|
|
||||||
allowAny: false,
|
|
||||||
allowValueMutation: true,
|
|
||||||
autoSelectFirst: true,
|
|
||||||
content: null,
|
|
||||||
_initialValues: null,
|
|
||||||
|
|
||||||
init() {
|
|
||||||
this._super();
|
|
||||||
|
|
||||||
this.noneValue = "__none__";
|
|
||||||
this._previousScrollParentOverflow = "auto";
|
|
||||||
this._previousCSSContext = {};
|
|
||||||
this.set("headerComponentOptions", Ember.Object.create());
|
|
||||||
this.set("rowComponentOptions", Ember.Object.create());
|
|
||||||
|
|
||||||
if ($(window).outerWidth(false) <= 420) {
|
|
||||||
this.setProperties({ filterable: false, autoFilterable: false });
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isNone(this.get("content"))) { this.set("content", []); }
|
|
||||||
this.set("value", this._castInteger(this.get("value")));
|
|
||||||
|
|
||||||
this.setInitialValues();
|
|
||||||
},
|
|
||||||
|
|
||||||
setInitialValues() {
|
|
||||||
this.set("_initialValues", this.getWithDefault("content", []).map((c) => {
|
|
||||||
return this._valueForContent(c);
|
|
||||||
}));
|
|
||||||
},
|
|
||||||
|
|
||||||
@computed("computedContent.[]", "computedValue.[]", "filter")
|
|
||||||
filteredContent(computedContent, computedValue, filter) {
|
|
||||||
return this.filteredContentFunction(computedContent, computedValue, filter);
|
|
||||||
},
|
|
||||||
|
|
||||||
filteredContentFunction(computedContent, computedValue, filter) {
|
|
||||||
if (isEmpty(filter)) { return computedContent; }
|
|
||||||
|
|
||||||
const lowerFilter = filter.toLowerCase();
|
|
||||||
return computedContent.filter(c => {
|
|
||||||
return get(c, "name").toLowerCase().indexOf(lowerFilter) > -1;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
formatRowContent(content) {
|
|
||||||
let originalContent;
|
|
||||||
|
|
||||||
if (typeof content === "string" || typeof content === "number") {
|
|
||||||
originalContent = {};
|
|
||||||
originalContent[this.get("valueAttribute")] = content;
|
|
||||||
originalContent[this.get("nameProperty")] = content;
|
|
||||||
} else {
|
|
||||||
originalContent = content;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
value: this._castInteger(this._valueForContent(content)),
|
|
||||||
name: this._nameForContent(content),
|
|
||||||
locked: false,
|
|
||||||
originalContent
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
formatContents(contents) {
|
|
||||||
return contents.map(content => this.formatRowContent(content));
|
|
||||||
},
|
|
||||||
|
|
||||||
@computed("filter", "filterable", "autoFilterable", "renderedFilterOnce")
|
|
||||||
shouldDisplayFilter(filter, filterable, autoFilterable, renderedFilterOnce) {
|
|
||||||
if (renderedFilterOnce === true || filterable === true) { return true; }
|
|
||||||
if (filter.length > 0 && autoFilterable === true) { return true; }
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
|
|
||||||
@computed("filter")
|
|
||||||
shouldDisplayCreateRow(filter) {
|
|
||||||
if (this.get("allowAny") === true && filter.length > 0) { return true; }
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
|
|
||||||
@computed("filter", "shouldDisplayCreateRow")
|
|
||||||
createRowContent(filter, shouldDisplayCreateRow) {
|
|
||||||
if (shouldDisplayCreateRow === true && !this.get("value").includes(filter)) {
|
|
||||||
return Ember.Object.create({ value: filter, name: filter });
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
@computed("content.[]", "value.[]")
|
|
||||||
computedContent(content) {
|
|
||||||
this._mutateValue();
|
|
||||||
return this.formatContents(content || []);
|
|
||||||
},
|
|
||||||
|
|
||||||
@computed("value", "none", "computedContent.firstObject.value")
|
|
||||||
computedValue(value, none, firstContentValue) {
|
|
||||||
if (isNone(value) && isNone(none) && this.get("autoSelectFirst") === true) {
|
|
||||||
return firstContentValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
return value;
|
|
||||||
},
|
|
||||||
|
|
||||||
@computed
|
|
||||||
templateForRow() { return () => null; },
|
|
||||||
|
|
||||||
@computed
|
|
||||||
templateForNoneRow() { return () => null; },
|
|
||||||
|
|
||||||
@computed
|
|
||||||
templateForCreateRow() { return () => null; },
|
|
||||||
|
|
||||||
@computed("none")
|
|
||||||
computedNone(none) {
|
|
||||||
if (isNone(none)) { return null; }
|
|
||||||
|
|
||||||
switch (typeof none) {
|
|
||||||
case "string":
|
|
||||||
return Ember.Object.create({ name: I18n.t(none), value: this.noneValue });
|
|
||||||
default:
|
|
||||||
return this.formatRowContent(none);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
@computed("computedValue", "computedContent.[]")
|
|
||||||
selectedContent(computedValue, computedContent) {
|
|
||||||
if (isNone(computedValue)) { return []; }
|
|
||||||
return [ computedContent.findBy("value", computedValue) ];
|
|
||||||
},
|
|
||||||
|
|
||||||
@on("didInsertElement")
|
|
||||||
_setupResizeListener() {
|
|
||||||
$(window).on("resize.select-box-kit", () => this.collapse() );
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
autoHighlightFunction() {
|
|
||||||
Ember.run.schedule("afterRender", () => {
|
|
||||||
if (!isNone(this.get("highlightedValue"))) { return; }
|
|
||||||
|
|
||||||
const filteredContent = this.get("filteredContent");
|
|
||||||
const display = this.get("shouldDisplayCreateRow");
|
|
||||||
const none = this.get("computedNone");
|
|
||||||
|
|
||||||
if (isNone(this.get("highlightedValue")) && !isEmpty(filteredContent)) {
|
|
||||||
this.send("onHighlight", get(filteredContent, "firstObject.value"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (display === true && isEmpty(filteredContent)) {
|
|
||||||
this.send("onHighlight", this.get("filter"));
|
|
||||||
}
|
|
||||||
else if (!isEmpty(filteredContent)) {
|
|
||||||
this.send("onHighlight", get(filteredContent, "firstObject.value"));
|
|
||||||
}
|
|
||||||
else if (isEmpty(filteredContent) && isPresent(none) && display === false) {
|
|
||||||
this.send("onHighlight", get(none, "value"));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
willFilterContent() {
|
|
||||||
this.expand();
|
|
||||||
this.set("highlightedValue", null);
|
|
||||||
},
|
|
||||||
didFilterContent() {
|
|
||||||
this.set("renderedFilterOnce", true);
|
|
||||||
this.autoHighlightFunction();
|
|
||||||
},
|
|
||||||
|
|
||||||
willCreateContent() { },
|
|
||||||
createContentFunction(input) {
|
|
||||||
this.get("content").pushObject(input);
|
|
||||||
this.send("onSelect", input);
|
|
||||||
},
|
|
||||||
didCreateContent() {
|
|
||||||
this.clearFilter();
|
|
||||||
this.autoHighlightFunction();
|
|
||||||
},
|
|
||||||
|
|
||||||
willHighlightValue() {},
|
|
||||||
highlightValueFunction(value) {
|
|
||||||
this.set("highlightedValue", value);
|
|
||||||
},
|
|
||||||
didHighlightValue() {},
|
|
||||||
|
|
||||||
willSelectValue() {
|
|
||||||
this.clearFilter();
|
|
||||||
this.set("highlightedValue", null);
|
|
||||||
},
|
|
||||||
selectValueFunction(value) {
|
|
||||||
this.set("value", value);
|
|
||||||
},
|
|
||||||
didSelectValue() {
|
|
||||||
this.collapse();
|
|
||||||
this.focus();
|
|
||||||
},
|
|
||||||
|
|
||||||
willDeselectValue() {
|
|
||||||
this.set("highlightedValue", null);
|
|
||||||
},
|
|
||||||
unsetValueFunction() {
|
|
||||||
this.set("value", null);
|
|
||||||
},
|
|
||||||
didDeselectValue() {
|
|
||||||
this.focus();
|
|
||||||
},
|
|
||||||
|
|
||||||
actions: {
|
|
||||||
onToggle() {
|
|
||||||
this.get("isExpanded") === true ? this.collapse() : this.expand();
|
|
||||||
},
|
|
||||||
|
|
||||||
onClearSelection() {
|
|
||||||
this.send("onDeselect", this.get("value"));
|
|
||||||
},
|
|
||||||
|
|
||||||
onHighlight(value) {
|
|
||||||
value = this._originalValueForValue(value);
|
|
||||||
this.willHighlightValue(value);
|
|
||||||
this.set("highlightedValue", value);
|
|
||||||
this.highlightValueFunction(value);
|
|
||||||
this.didHighlightValue(value);
|
|
||||||
},
|
|
||||||
|
|
||||||
onCreateContent(input) {
|
|
||||||
this.willCreateContent(input);
|
|
||||||
this.createContentFunction(input);
|
|
||||||
this.didCreateContent(input);
|
|
||||||
},
|
|
||||||
|
|
||||||
onSelect(value) {
|
|
||||||
if (value === "") { value = null; }
|
|
||||||
this.willSelectValue(value);
|
|
||||||
this.selectValueFunction(value);
|
|
||||||
this.didSelectValue(value);
|
|
||||||
},
|
|
||||||
|
|
||||||
onDeselect(value) {
|
|
||||||
value = this._originalValueForValue(value);
|
|
||||||
this.willDeselectValue(value);
|
|
||||||
this.unsetValueFunction(value);
|
|
||||||
this.didSelectValue(value);
|
|
||||||
},
|
|
||||||
|
|
||||||
onFilterChange(_filter) {
|
|
||||||
this.willFilterContent(_filter);
|
|
||||||
this.set("filter", _filter);
|
|
||||||
this.didFilterContent(_filter);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
clearFilter() {
|
|
||||||
this.$filterInput().val("");
|
|
||||||
this.setProperties({ filter: "" });
|
|
||||||
},
|
|
||||||
|
|
||||||
@on("didReceiveAttrs")
|
|
||||||
_mutateValue() {
|
|
||||||
if (this.get("allowValueMutation") !== true) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const none = isNone(this.get("none"));
|
|
||||||
const emptyValue = isEmpty(this.get("value"));
|
|
||||||
|
|
||||||
if (none && emptyValue) {
|
|
||||||
Ember.run.scheduleOnce("sync", () => {
|
|
||||||
if (!isEmpty(this.get("computedContent"))) {
|
|
||||||
const firstValue = this.get("computedContent.firstObject.value");
|
|
||||||
this.set("value", firstValue);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -1,5 +0,0 @@
|
||||||
export default Ember.Component.extend({
|
|
||||||
layoutName: "select-box-kit/templates/components/select-box-kit/select-box-kit-collection",
|
|
||||||
classNames: "select-box-kit-collection",
|
|
||||||
tagName: "ul"
|
|
||||||
});
|
|
|
@ -1,10 +0,0 @@
|
||||||
import SelectBoxKitRowComponent from "select-box-kit/components/select-box-kit/select-box-kit-row";
|
|
||||||
|
|
||||||
export default SelectBoxKitRowComponent.extend({
|
|
||||||
layoutName: "select-box-kit/templates/components/select-box-kit/select-box-kit-row",
|
|
||||||
classNames: "create",
|
|
||||||
|
|
||||||
click() {
|
|
||||||
this.sendAction("onCreateContent", this.get("content.name"));
|
|
||||||
},
|
|
||||||
});
|
|
|
@ -1,28 +0,0 @@
|
||||||
import computed from 'ember-addons/ember-computed-decorators';
|
|
||||||
|
|
||||||
export default Ember.Component.extend({
|
|
||||||
layoutName: "select-box-kit/templates/components/select-box-kit/select-box-kit-header",
|
|
||||||
classNames: "select-box-kit-header",
|
|
||||||
classNameBindings: ["isFocused"],
|
|
||||||
attributeBindings: ["selectedName:data-name"],
|
|
||||||
shouldDisplaySelectedName: true,
|
|
||||||
|
|
||||||
@computed("options.shouldDisplaySelectedName")
|
|
||||||
shouldDisplaySelectedName(should) {
|
|
||||||
if (Ember.isNone(should)) { return true; }
|
|
||||||
return should;
|
|
||||||
},
|
|
||||||
|
|
||||||
@computed("options.selectedName", "selectedContent.firstObject.name")
|
|
||||||
selectedName(optionsSelectedName, firstSelectedContentName) {
|
|
||||||
if (Ember.isNone(optionsSelectedName)) {
|
|
||||||
return firstSelectedContentName;
|
|
||||||
}
|
|
||||||
return optionsSelectedName;
|
|
||||||
},
|
|
||||||
|
|
||||||
@computed("options.icon")
|
|
||||||
icon(optionsIcon) { return optionsIcon; },
|
|
||||||
|
|
||||||
click() { this.sendAction("onToggle"); }
|
|
||||||
});
|
|
|
@ -1,10 +0,0 @@
|
||||||
import SelectBoxKitRowComponent from "select-box-kit/components/select-box-kit/select-box-kit-row";
|
|
||||||
|
|
||||||
export default SelectBoxKitRowComponent.extend({
|
|
||||||
layoutName: "select-box-kit/templates/components/select-box-kit/select-box-kit-row",
|
|
||||||
classNames: "none",
|
|
||||||
|
|
||||||
click() {
|
|
||||||
this.sendAction("onClearSelection");
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -1,70 +0,0 @@
|
||||||
import { iconHTML } from 'discourse-common/lib/icon-library';
|
|
||||||
import { on } from 'ember-addons/ember-computed-decorators';
|
|
||||||
import computed from 'ember-addons/ember-computed-decorators';
|
|
||||||
const { run, isPresent } = Ember;
|
|
||||||
import UtilsMixin from "select-box-kit/mixins/utils";
|
|
||||||
|
|
||||||
export default Ember.Component.extend(UtilsMixin, {
|
|
||||||
layoutName: "select-box-kit/templates/components/select-box-kit/select-box-kit-row",
|
|
||||||
classNames: "select-box-kit-row",
|
|
||||||
tagName: "li",
|
|
||||||
tabIndex: -1,
|
|
||||||
attributeBindings: [
|
|
||||||
"tabIndex",
|
|
||||||
"title",
|
|
||||||
"content.value:data-value",
|
|
||||||
"content.name:data-name"
|
|
||||||
],
|
|
||||||
classNameBindings: ["isHighlighted", "isSelected"],
|
|
||||||
clicked: false,
|
|
||||||
|
|
||||||
@computed("content.originalContent.title", "content.name")
|
|
||||||
title(title, name) {
|
|
||||||
return title || name;
|
|
||||||
},
|
|
||||||
|
|
||||||
@computed("templateForRow")
|
|
||||||
template(templateForRow) { return templateForRow(this); },
|
|
||||||
|
|
||||||
@on("didReceiveAttrs")
|
|
||||||
_setSelectionState() {
|
|
||||||
const contentValue = this.get("content.value");
|
|
||||||
|
|
||||||
this.set("isSelected", this.get("value") === contentValue);
|
|
||||||
this.set("isHighlighted", this.get("highlightedValue") === contentValue);
|
|
||||||
},
|
|
||||||
|
|
||||||
@on("willDestroyElement")
|
|
||||||
_clearDebounce() {
|
|
||||||
const hoverDebounce = this.get("hoverDebounce");
|
|
||||||
if (isPresent(hoverDebounce)) { run.cancel(hoverDebounce); }
|
|
||||||
},
|
|
||||||
|
|
||||||
@computed("content.originalContent.icon", "content.originalContent.iconClass")
|
|
||||||
icon(icon, cssClass) {
|
|
||||||
if (icon) {
|
|
||||||
return iconHTML(icon, { class: cssClass });
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
|
|
||||||
mouseEnter() {
|
|
||||||
this.set("hoverDebounce", run.debounce(this, this._sendOnHighlightAction, 32));
|
|
||||||
},
|
|
||||||
|
|
||||||
click() {
|
|
||||||
this._sendOnSelectAction();
|
|
||||||
},
|
|
||||||
|
|
||||||
_sendOnSelectAction() {
|
|
||||||
if (this.get("clicked") === false) {
|
|
||||||
this.set("clicked", true);
|
|
||||||
this.sendAction("onSelect", this.get("content.value"));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
_sendOnHighlightAction() {
|
|
||||||
this.sendAction("onHighlight", this.get("content.value"));
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -1,12 +0,0 @@
|
||||||
import NotificationOptionsComponent from "select-box-kit/components/notifications-button";
|
|
||||||
|
|
||||||
export default NotificationOptionsComponent.extend({
|
|
||||||
classNames: "tag-notifications-button",
|
|
||||||
i18nPrefix: "tagging.notifications",
|
|
||||||
showFullTitle: false,
|
|
||||||
headerComponent: "tag-notifications-button/tag-notifications-button-header",
|
|
||||||
|
|
||||||
selectValueFunction(value) {
|
|
||||||
this.sendAction("action", value);
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -1,13 +0,0 @@
|
||||||
import NotificationButtonHeader from "select-box-kit/components/notifications-button/notifications-button-header";
|
|
||||||
import computed from "ember-addons/ember-computed-decorators";
|
|
||||||
import { iconHTML } from 'discourse-common/lib/icon-library';
|
|
||||||
|
|
||||||
export default NotificationButtonHeader.extend({
|
|
||||||
classNames: "tag-notifications-button-header",
|
|
||||||
shouldDisplaySelectedName: false,
|
|
||||||
|
|
||||||
@computed("_selectedDetails.icon", "_selectedDetails.key")
|
|
||||||
icon() {
|
|
||||||
return `${this._super()}${iconHTML("caret-down")}`.htmlSafe();
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -1,222 +0,0 @@
|
||||||
export default Ember.Mixin.create({
|
|
||||||
init() {
|
|
||||||
this._super();
|
|
||||||
|
|
||||||
this.keys = {
|
|
||||||
TAB: 9,
|
|
||||||
ENTER: 13,
|
|
||||||
ESC: 27,
|
|
||||||
SPACE: 32,
|
|
||||||
LEFT: 37,
|
|
||||||
UP: 38,
|
|
||||||
RIGHT: 39,
|
|
||||||
DOWN: 40,
|
|
||||||
SHIFT: 16,
|
|
||||||
CTRL: 17,
|
|
||||||
ALT: 18,
|
|
||||||
PAGE_UP: 33,
|
|
||||||
PAGE_DOWN: 34,
|
|
||||||
HOME: 36,
|
|
||||||
END: 35,
|
|
||||||
BACKSPACE: 8
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
willDestroyElement() {
|
|
||||||
this._super();
|
|
||||||
|
|
||||||
$(document)
|
|
||||||
.off("mousedown.select-box-kit")
|
|
||||||
.off("touchstart.select-box-kit");
|
|
||||||
|
|
||||||
this.$offscreenInput()
|
|
||||||
.off("focus.select-box-kit")
|
|
||||||
.off("focusin.select-box-kit")
|
|
||||||
.off("blur.select-box-kit")
|
|
||||||
.off("keypress.select-box-kit")
|
|
||||||
.off("keydown.select-box-kit");
|
|
||||||
|
|
||||||
this.$filterInput()
|
|
||||||
.off("change.select-box-kit")
|
|
||||||
.off("keypress.select-box-kit")
|
|
||||||
.off("keydown.select-box-kit");
|
|
||||||
},
|
|
||||||
|
|
||||||
didInsertElement() {
|
|
||||||
this._super();
|
|
||||||
|
|
||||||
$(document)
|
|
||||||
.on("mousedown.select-box-kit, touchstart.select-box-kit", event => {
|
|
||||||
if (Ember.isNone(this.get("element"))) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.get("element").contains(event.target)) { return; }
|
|
||||||
this.clickOutside(event);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.$offscreenInput()
|
|
||||||
.on("blur.select-box-kit", () => {
|
|
||||||
if (this.get("isExpanded") === false && this.get("isFocused") === true) {
|
|
||||||
this.close();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.on("focus.select-box-kit", (event) => {
|
|
||||||
this.set("isFocused", true);
|
|
||||||
this._killEvent(event);
|
|
||||||
})
|
|
||||||
.on("focusin.select-box-kit", (event) => {
|
|
||||||
this.set("isFocused", true);
|
|
||||||
this._killEvent(event);
|
|
||||||
})
|
|
||||||
.on("keydown.select-box-kit", (event) => {
|
|
||||||
const keyCode = event.keyCode || event.which;
|
|
||||||
|
|
||||||
if (keyCode === this.keys.TAB) { this._handleTabOnKeyDown(event); }
|
|
||||||
if (keyCode === this.keys.ESC) { this._handleEscOnKeyDown(event); }
|
|
||||||
if (keyCode === this.keys.UP || keyCode === this.keys.DOWN) {
|
|
||||||
this._handleArrowKey(keyCode, event);
|
|
||||||
}
|
|
||||||
if (keyCode === this.keys.BACKSPACE) {
|
|
||||||
this.expand();
|
|
||||||
|
|
||||||
if (this.$filterInput().is(":visible")) {
|
|
||||||
this.$filterInput().focus().trigger(event).trigger("change");
|
|
||||||
}
|
|
||||||
|
|
||||||
return event;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
})
|
|
||||||
.on("keypress.select-box-kit", (event) => {
|
|
||||||
const keyCode = event.keyCode || event.which;
|
|
||||||
|
|
||||||
switch (keyCode) {
|
|
||||||
case this.keys.ENTER:
|
|
||||||
if (this.get("isExpanded") === false) {
|
|
||||||
this.expand();
|
|
||||||
} else if (this.$highlightedRow().length === 1) {
|
|
||||||
this.$highlightedRow().click();
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
case this.keys.BACKSPACE:
|
|
||||||
return event;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this._isSpecialKey(keyCode) === false && event.metaKey === false) {
|
|
||||||
this.expand();
|
|
||||||
|
|
||||||
if (this.get("filterable") === true || this.get("autoFilterable")) {
|
|
||||||
this.set("renderedFilterOnce", true);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ember.run.schedule("afterRender", () => {
|
|
||||||
this.$filterInput()
|
|
||||||
.focus()
|
|
||||||
.val(this.$filterInput().val() + String.fromCharCode(keyCode));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.$filterInput()
|
|
||||||
.on("change.select-box-kit", (event) => {
|
|
||||||
this.send("onFilterChange", $(event.target).val());
|
|
||||||
})
|
|
||||||
.on("keydown.select-box-kit", (event) => {
|
|
||||||
const keyCode = event.keyCode || event.which;
|
|
||||||
|
|
||||||
if (keyCode === this.keys.TAB) { this._handleTabOnKeyDown(event); }
|
|
||||||
if (keyCode === this.keys.ESC) { this._handleEscOnKeyDown(event); }
|
|
||||||
if (keyCode === this.keys.UP || keyCode === this.keys.DOWN) {
|
|
||||||
this._handleArrowKey(keyCode, event);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.on("keypress.select-box-kit", (event) => {
|
|
||||||
const keyCode = event.keyCode || event.which;
|
|
||||||
|
|
||||||
if ([
|
|
||||||
this.keys.RIGHT,
|
|
||||||
this.keys.LEFT,
|
|
||||||
this.keys.BACKSPACE,
|
|
||||||
this.keys.SPACE,
|
|
||||||
].includes(keyCode) || event.metaKey === true) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (keyCode === this.keys.TAB && this.get("isExpanded") === false) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this._isSpecialKey(keyCode) === true) {
|
|
||||||
this.$offscreenInput().focus().trigger(event);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
_handleEscOnKeyDown(event) {
|
|
||||||
this.unfocus();
|
|
||||||
this._killEvent(event);
|
|
||||||
},
|
|
||||||
|
|
||||||
_handleTabOnKeyDown(event) {
|
|
||||||
if (this.get("isExpanded") === false) {
|
|
||||||
this.unfocus();
|
|
||||||
return true;
|
|
||||||
} else if (this.$highlightedRow().length === 1) {
|
|
||||||
this._killEvent(event);
|
|
||||||
this.$highlightedRow().click();
|
|
||||||
this.focus();
|
|
||||||
} else {
|
|
||||||
this.unfocus();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
|
|
||||||
_handleArrowKey(keyCode, event) {
|
|
||||||
if (this.get("isExpanded") === false) { this.expand(); }
|
|
||||||
this._killEvent(event);
|
|
||||||
const $rows = this.$rows();
|
|
||||||
|
|
||||||
if ($rows.length <= 0) { return; }
|
|
||||||
if ($rows.length === 1) {
|
|
||||||
this._rowSelection($rows, 0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const direction = keyCode === 38 ? -1 : 1;
|
|
||||||
|
|
||||||
Ember.run.throttle(this, this._moveHighlight, direction, $rows, 32);
|
|
||||||
},
|
|
||||||
|
|
||||||
_moveHighlight(direction, $rows) {
|
|
||||||
const currentIndex = $rows.index(this.$highlightedRow());
|
|
||||||
let nextIndex = currentIndex + direction;
|
|
||||||
|
|
||||||
if (nextIndex < 0) {
|
|
||||||
nextIndex = $rows.length - 1;
|
|
||||||
} else if (nextIndex >= $rows.length) {
|
|
||||||
nextIndex = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._rowSelection($rows, nextIndex);
|
|
||||||
},
|
|
||||||
|
|
||||||
_rowSelection($rows, nextIndex) {
|
|
||||||
const highlightableValue = $rows.eq(nextIndex).attr("data-value");
|
|
||||||
const $highlightableRow = this.$findRowByValue(highlightableValue);
|
|
||||||
|
|
||||||
Ember.run.schedule("afterRender", () => {
|
|
||||||
$highlightableRow.trigger("mouseover").focus();
|
|
||||||
this.focus();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
_isSpecialKey(keyCode) {
|
|
||||||
return _.values(this.keys).includes(keyCode);
|
|
||||||
},
|
|
||||||
});
|
|
|
@ -1,15 +0,0 @@
|
||||||
{{#if icon}}
|
|
||||||
{{{icon}}}
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
<span class="selected-name" title={{selectedName}}>
|
|
||||||
{{{selectedName}}}
|
|
||||||
</span>
|
|
||||||
|
|
||||||
{{#if shouldDisplayClearableButton}}
|
|
||||||
<button class="btn-clear" {{action onClearSelection bubbles=false}}>
|
|
||||||
{{d-icon 'times'}}
|
|
||||||
</button>
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
{{d-icon caretIcon class="caret-icon"}}
|
|
|
@ -1,18 +0,0 @@
|
||||||
<button
|
|
||||||
class="btn {{if shouldDisplaySelectedName 'btn-icon-text' 'no-text btn-icon'}}"
|
|
||||||
aria-label="{{selectedName}}"
|
|
||||||
type="button"
|
|
||||||
tabindex="-1"
|
|
||||||
title="{{selectedName}}">
|
|
||||||
|
|
||||||
{{#if icon}}
|
|
||||||
{{{icon}}}
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
{{#if shouldDisplaySelectedName}}
|
|
||||||
<span class="d-button-label selected-name">
|
|
||||||
{{selectedName}}
|
|
||||||
</span>
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
</button>
|
|
|
@ -1,13 +0,0 @@
|
||||||
<ul class="choices">
|
|
||||||
{{#each selectedContent as |selectedContent|}}
|
|
||||||
{{component selectedNameComponent onDeselect=onDeselect content=selectedContent}}
|
|
||||||
{{/each}}
|
|
||||||
<li class="filter">
|
|
||||||
{{component "select-box-kit/select-box-kit-filter"
|
|
||||||
onFilterChange=onFilterChange
|
|
||||||
shouldDisplayFilter=shouldDisplayFilter
|
|
||||||
isFocused=isFocused
|
|
||||||
filter=filter
|
|
||||||
}}
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
|
@ -1,9 +0,0 @@
|
||||||
<span class="name">
|
|
||||||
{{#unless isLocked}}
|
|
||||||
<span class="delete-icon" {{action onDeselect content.value bubbles=false}}>
|
|
||||||
{{d-icon "times"}}
|
|
||||||
</span>
|
|
||||||
{{/unless}}
|
|
||||||
|
|
||||||
{{content.name}}
|
|
||||||
</span>
|
|
|
@ -1,7 +0,0 @@
|
||||||
{{#if icon}}
|
|
||||||
{{{icon}}}
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
<span class="selected-name" title={{selectedName}}>
|
|
||||||
{{{selectedName}}}
|
|
||||||
</span>
|
|
|
@ -1,9 +0,0 @@
|
||||||
{{#if template}}
|
|
||||||
{{{template}}}
|
|
||||||
{{else}}
|
|
||||||
{{#if icon}}
|
|
||||||
{{{icon}}}
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
<span class="name">{{content.name}}</span>
|
|
||||||
{{/if}}
|
|
|
@ -1,21 +1,18 @@
|
||||||
import { iconHTML } from 'discourse-common/lib/icon-library';
|
import DropdownSelectBox from "select-kit/components/dropdown-select-box";
|
||||||
import DropdownSelectBox from "select-box-kit/components/dropdown-select-box";
|
|
||||||
import computed from "ember-addons/ember-computed-decorators";
|
import computed from "ember-addons/ember-computed-decorators";
|
||||||
import { on } from "ember-addons/ember-computed-decorators";
|
|
||||||
|
|
||||||
export default DropdownSelectBox.extend({
|
export default DropdownSelectBox.extend({
|
||||||
headerText: "admin.flags.agree",
|
pluginApiIdentifiers: ["admin-agree-flag-dropdown"],
|
||||||
headerIcon: "thumbs-o-up",
|
|
||||||
classNames: ["agree-flag", "admin-agree-flag-dropdown"],
|
classNames: ["agree-flag", "admin-agree-flag-dropdown"],
|
||||||
adminTools: Ember.inject.service(),
|
adminTools: Ember.inject.service(),
|
||||||
nameProperty: "label",
|
nameProperty: "label",
|
||||||
|
allowInitialValueMutation: false,
|
||||||
|
headerIcon: "thumbs-o-up",
|
||||||
|
|
||||||
@on("didReceiveAttrs")
|
computeHeaderContent() {
|
||||||
_setAdminAgreeDropdownOptions() {
|
let content = this.baseHeaderComputedContent();
|
||||||
this.get('headerComponentOptions').setProperties({
|
content.name = `${I18n.t("admin.flags.agree")}...`;
|
||||||
selectedName: `${I18n.t(this.get("headerText"))} ...`,
|
return content;
|
||||||
icon: iconHTML("thumbs-o-up")
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
@computed("adminTools", "post.user")
|
@computed("adminTools", "post.user")
|
||||||
|
@ -25,9 +22,10 @@ export default DropdownSelectBox.extend({
|
||||||
|
|
||||||
canDeleteSpammer: Ember.computed.and("spammerDetails.canDelete", "post.flaggedForSpam"),
|
canDeleteSpammer: Ember.computed.and("spammerDetails.canDelete", "post.flaggedForSpam"),
|
||||||
|
|
||||||
@computed("post", "canDeleteSpammer")
|
computeContent() {
|
||||||
content(post, canDeleteSpammer) {
|
|
||||||
const content = [];
|
const content = [];
|
||||||
|
const post = this.get("post");
|
||||||
|
const canDeleteSpammer = this.get("canDeleteSpammer");
|
||||||
|
|
||||||
if (post.user_deleted) {
|
if (post.user_deleted) {
|
||||||
content.push({
|
content.push({
|
||||||
|
@ -70,8 +68,9 @@ export default DropdownSelectBox.extend({
|
||||||
return content;
|
return content;
|
||||||
},
|
},
|
||||||
|
|
||||||
selectValueFunction(value) {
|
mutateValue(value) {
|
||||||
Ember.get(this._contentForValue(value), "action")();
|
const computedContentItem = this.get("computedContent").findBy("value", value);
|
||||||
|
Ember.get(computedContentItem, "originalContent.action")();
|
||||||
},
|
},
|
||||||
|
|
||||||
actions: {
|
actions: {
|
|
@ -1,20 +1,16 @@
|
||||||
import { iconHTML } from 'discourse-common/lib/icon-library';
|
import DropdownSelectBox from "select-kit/components/dropdown-select-box";
|
||||||
import DropdownSelectBox from "select-box-kit/components/dropdown-select-box";
|
|
||||||
import computed from "ember-addons/ember-computed-decorators";
|
import computed from "ember-addons/ember-computed-decorators";
|
||||||
import { on } from "ember-addons/ember-computed-decorators";
|
|
||||||
|
|
||||||
export default DropdownSelectBox.extend({
|
export default DropdownSelectBox.extend({
|
||||||
headerText: "admin.flags.delete",
|
|
||||||
classNames: ["delete-flag", "admin-delete-flag-dropdown"],
|
classNames: ["delete-flag", "admin-delete-flag-dropdown"],
|
||||||
adminTools: Ember.inject.service(),
|
adminTools: Ember.inject.service(),
|
||||||
nameProperty: "label",
|
nameProperty: "label",
|
||||||
|
headerIcon: "trash-o",
|
||||||
|
|
||||||
@on("didReceiveAttrs")
|
computeHeaderContent() {
|
||||||
_setAdminDeleteDropdownOptions() {
|
let content = this.baseHeaderComputedContent();
|
||||||
this.get('headerComponentOptions').setProperties({
|
content.name = I18n.t("admin.flags.delete");
|
||||||
selectedName: `${I18n.t(this.get("headerText"))} ...`,
|
return content;
|
||||||
icon: iconHTML("trash-o")
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
@computed("adminTools", "post.user")
|
@computed("adminTools", "post.user")
|
||||||
|
@ -24,9 +20,9 @@ export default DropdownSelectBox.extend({
|
||||||
|
|
||||||
canDeleteSpammer: Ember.computed.and("spammerDetails.canDelete", "post.flaggedForSpam"),
|
canDeleteSpammer: Ember.computed.and("spammerDetails.canDelete", "post.flaggedForSpam"),
|
||||||
|
|
||||||
@computed("post", "canDeleteSpammer")
|
computeContent() {
|
||||||
content(post, canDeleteSpammer) {
|
|
||||||
const content = [];
|
const content = [];
|
||||||
|
const canDeleteSpammer = this.get("canDeleteSpammer");
|
||||||
|
|
||||||
content.push({
|
content.push({
|
||||||
icon: "external-link",
|
icon: "external-link",
|
||||||
|
@ -57,8 +53,9 @@ export default DropdownSelectBox.extend({
|
||||||
return content;
|
return content;
|
||||||
},
|
},
|
||||||
|
|
||||||
selectValueFunction(value) {
|
mutateValue(value) {
|
||||||
Ember.get(this._contentForValue(value), "action")();
|
const computedContentItem = this.get("computedContent").findBy("value", value);
|
||||||
|
Ember.get(computedContentItem, "originalContent.action")();
|
||||||
},
|
},
|
||||||
|
|
||||||
actions: {
|
actions: {
|
|
@ -0,0 +1,51 @@
|
||||||
|
import MultiSelectComponent from "select-kit/components/multi-select";
|
||||||
|
const { makeArray } = Ember;
|
||||||
|
|
||||||
|
export default MultiSelectComponent.extend({
|
||||||
|
pluginApiIdentifiers: ["admin-group-selector"],
|
||||||
|
classNames: "admin-group-selector",
|
||||||
|
selected: null,
|
||||||
|
available: null,
|
||||||
|
allowAny: false,
|
||||||
|
|
||||||
|
computeValues() {
|
||||||
|
return makeArray(this.get("selected"))
|
||||||
|
.map(s => this.valueForContentItem(s));
|
||||||
|
},
|
||||||
|
|
||||||
|
computeContent() {
|
||||||
|
return makeArray(this.get("available"));
|
||||||
|
},
|
||||||
|
|
||||||
|
computeContentItem(contentItem, name) {
|
||||||
|
let computedContent = this.baseComputedContentItem(contentItem, name);
|
||||||
|
computedContent.locked = contentItem.automatic;
|
||||||
|
return computedContent;
|
||||||
|
},
|
||||||
|
|
||||||
|
mutateValues(values) {
|
||||||
|
if (values.length > this.get("selected").length) {
|
||||||
|
const newValues = values
|
||||||
|
.filter(v => !this.get("selected")
|
||||||
|
.map(s => this.valueForContentItem(s))
|
||||||
|
.includes(v));
|
||||||
|
|
||||||
|
newValues.forEach(value => {
|
||||||
|
const actionContext = this.get("available")
|
||||||
|
.findBy(this.get("valueAttribute"), parseInt(value, 10));
|
||||||
|
|
||||||
|
this.triggerAction({ action: "groupAdded", actionContext });
|
||||||
|
});
|
||||||
|
} else if (values.length < this.get("selected").length) {
|
||||||
|
const selected = this.get("selected")
|
||||||
|
.filter(s => !values.includes(this.valueForContentItem(s)));
|
||||||
|
|
||||||
|
selected.forEach(s => {
|
||||||
|
this.triggerAction({
|
||||||
|
action: "groupRemoved",
|
||||||
|
actionContext: this.valueForContentItem(s)
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
|
@ -1,21 +1,15 @@
|
||||||
import DropdownSelectBoxComponent from "select-box-kit/components/dropdown-select-box";
|
import DropdownSelectBoxComponent from "select-kit/components/dropdown-select-box";
|
||||||
import { iconHTML } from "discourse-common/lib/icon-library";
|
|
||||||
import computed from "ember-addons/ember-computed-decorators";
|
|
||||||
import { on } from "ember-addons/ember-computed-decorators";
|
|
||||||
|
|
||||||
export default DropdownSelectBoxComponent.extend({
|
export default DropdownSelectBoxComponent.extend({
|
||||||
|
pluginApiIdentifiers: ["categories-admin-dropdown"],
|
||||||
classNames: "categories-admin-dropdown",
|
classNames: "categories-admin-dropdown",
|
||||||
|
showFullTitle: false,
|
||||||
|
allowInitialValueMutation: false,
|
||||||
|
headerIcon: ["bars", "caret-down"],
|
||||||
|
|
||||||
@on("didReceiveAttrs")
|
autoHighlight() {},
|
||||||
_setComponentOptions() {
|
|
||||||
this.get("headerComponentOptions").setProperties({
|
|
||||||
shouldDisplaySelectedName: false,
|
|
||||||
icon: `${iconHTML('bars')}${iconHTML('caret-down')}`.htmlSafe(),
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
@computed
|
computeContent() {
|
||||||
content() {
|
|
||||||
const items = [
|
const items = [
|
||||||
{
|
{
|
||||||
id: "create",
|
id: "create",
|
||||||
|
@ -38,8 +32,7 @@ export default DropdownSelectBoxComponent.extend({
|
||||||
return items;
|
return items;
|
||||||
},
|
},
|
||||||
|
|
||||||
selectValueFunction(value) {
|
mutateValue(value) {
|
||||||
this.get(value)();
|
this.get(value)();
|
||||||
this.set("value", null);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
|
@ -0,0 +1,92 @@
|
||||||
|
import ComboBoxComponent from "select-kit/components/combo-box";
|
||||||
|
import { on } from "ember-addons/ember-computed-decorators";
|
||||||
|
import computed from "ember-addons/ember-computed-decorators";
|
||||||
|
import PermissionType from "discourse/models/permission-type";
|
||||||
|
import Category from "discourse/models/category";
|
||||||
|
const { get, isNone, isEmpty } = Ember;
|
||||||
|
|
||||||
|
export default ComboBoxComponent.extend({
|
||||||
|
pluginApiIdentifiers: ["category-chooser"],
|
||||||
|
classNames: "category-chooser",
|
||||||
|
filterable: true,
|
||||||
|
castInteger: true,
|
||||||
|
allowUncategorized: false,
|
||||||
|
rowComponent: "category-row",
|
||||||
|
noneRowComponent: "none-category-row",
|
||||||
|
allowSubCategories: true,
|
||||||
|
|
||||||
|
filterComputedContent(computedContent, computedValue, filter) {
|
||||||
|
if (isEmpty(filter)) { return computedContent; }
|
||||||
|
|
||||||
|
const _matchFunction = (f, text) => {
|
||||||
|
return text.toLowerCase().indexOf(f) > -1;
|
||||||
|
};
|
||||||
|
const lowerFilter = filter.toLowerCase();
|
||||||
|
|
||||||
|
return computedContent.filter(c => {
|
||||||
|
const category = Category.findById(get(c, "value"));
|
||||||
|
const text = get(c, "name");
|
||||||
|
if (category && category.get("parentCategory")) {
|
||||||
|
const categoryName = category.get("parentCategory.name");
|
||||||
|
return _matchFunction(lowerFilter, text) || _matchFunction(lowerFilter, categoryName);
|
||||||
|
} else {
|
||||||
|
return _matchFunction(lowerFilter, text);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
@computed("rootNone", "rootNoneLabel")
|
||||||
|
none(rootNone, rootNoneLabel) {
|
||||||
|
if (this.siteSettings.allow_uncategorized_topics || this.get("allowUncategorized")) {
|
||||||
|
if (!isNone(rootNone)) {
|
||||||
|
return rootNoneLabel || "category.none";
|
||||||
|
} else {
|
||||||
|
return Category.findUncategorized();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return "category.choose";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
@on("didRender")
|
||||||
|
_bindComposerResizing() {
|
||||||
|
this.appEvents.on("composer:resized", this, this.applyDirection);
|
||||||
|
},
|
||||||
|
|
||||||
|
@on("willDestroyElement")
|
||||||
|
_unbindComposerResizing() {
|
||||||
|
this.appEvents.off("composer:resized");
|
||||||
|
},
|
||||||
|
|
||||||
|
computeContent() {
|
||||||
|
const categories = Discourse.SiteSettings.fixed_category_positions_on_create ?
|
||||||
|
Category.list() :
|
||||||
|
Category.listByActivity();
|
||||||
|
|
||||||
|
let scopedCategoryId = this.get("scopedCategoryId");
|
||||||
|
if (scopedCategoryId) {
|
||||||
|
const scopedCat = Category.findById(scopedCategoryId);
|
||||||
|
scopedCategoryId = scopedCat.get("parent_category_id") || scopedCat.get("id");
|
||||||
|
}
|
||||||
|
|
||||||
|
const excludeCategoryId = this.get("excludeCategoryId");
|
||||||
|
|
||||||
|
return categories.filter(c => {
|
||||||
|
const categoryId = this.valueForContentItem(c);
|
||||||
|
|
||||||
|
if (scopedCategoryId && categoryId !== scopedCategoryId && get(c, "parent_category_id") !== scopedCategoryId) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.get("allowSubCategories") === false && c.get("parentCategory") ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((this.get("allowUncategorized") === false && get(c, "isUncategorizedCategory")) || excludeCategoryId === categoryId) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return get(c, "permission") === PermissionType.FULL;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,20 @@
|
||||||
|
import NotificationOptionsComponent from "select-kit/components/notifications-button";
|
||||||
|
import computed from "ember-addons/ember-computed-decorators";
|
||||||
|
|
||||||
|
export default NotificationOptionsComponent.extend({
|
||||||
|
pluginApiIdentifiers: ["category-notifications-button"],
|
||||||
|
classNames: "category-notifications-button",
|
||||||
|
isHidden: Ember.computed.or("category.deleted", "site.isMobileDevice"),
|
||||||
|
i18nPrefix: "category.notifications",
|
||||||
|
showFullTitle: false,
|
||||||
|
allowInitialValueMutation: false,
|
||||||
|
|
||||||
|
mutateValue(value) {
|
||||||
|
this.get("category").setNotification(value);
|
||||||
|
},
|
||||||
|
|
||||||
|
@computed("iconForSelectedDetails")
|
||||||
|
headerIcon(iconForSelectedDetails) {
|
||||||
|
return [iconForSelectedDetails, "caret-down"];
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,63 @@
|
||||||
|
import SelectKitRowComponent from "select-kit/components/select-kit/select-kit-row";
|
||||||
|
import computed from "ember-addons/ember-computed-decorators";
|
||||||
|
import Category from "discourse/models/category";
|
||||||
|
import { categoryBadgeHTML } from "discourse/helpers/category-link";
|
||||||
|
|
||||||
|
export default SelectKitRowComponent.extend({
|
||||||
|
layoutName: "select-kit/templates/components/category-row",
|
||||||
|
classNames: "category-row",
|
||||||
|
displayCategoryDescription: true,
|
||||||
|
|
||||||
|
@computed("computedContent.value", "computedContent.name")
|
||||||
|
category(value, name) {
|
||||||
|
if (Ember.isEmpty(value)) {
|
||||||
|
const uncat = Category.findUncategorized();
|
||||||
|
if (uncat && uncat.get("name") === name) {
|
||||||
|
return uncat;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Category.findById(parseInt(value, 10));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
@computed("category")
|
||||||
|
badgeForCategory(category) {
|
||||||
|
return categoryBadgeHTML(category, {
|
||||||
|
link: false,
|
||||||
|
allowUncategorized: true,
|
||||||
|
hideParent: true
|
||||||
|
}).htmlSafe();
|
||||||
|
},
|
||||||
|
|
||||||
|
@computed("parentCategory")
|
||||||
|
badgeForParentCategory(parentCategory) {
|
||||||
|
return categoryBadgeHTML(parentCategory, {link: false}).htmlSafe();
|
||||||
|
},
|
||||||
|
|
||||||
|
@computed("parentCategoryid")
|
||||||
|
parentCategory(parentCategoryId) {
|
||||||
|
return Category.findById(parentCategoryId);
|
||||||
|
},
|
||||||
|
|
||||||
|
@computed("parentCategoryid")
|
||||||
|
hasParentCategory(parentCategoryid) {
|
||||||
|
return !Ember.isNone(parentCategoryid);
|
||||||
|
},
|
||||||
|
|
||||||
|
@computed("category")
|
||||||
|
parentCategoryid(category) {
|
||||||
|
return category.get("parent_category_id");
|
||||||
|
},
|
||||||
|
|
||||||
|
topicCount: Ember.computed.alias("category.topic_count"),
|
||||||
|
|
||||||
|
@computed("options.displayCategoryDescription", "category.description")
|
||||||
|
hasDescription(displayCategoryDescription, description) {
|
||||||
|
return displayCategoryDescription && description && description !== "null";
|
||||||
|
},
|
||||||
|
|
||||||
|
@computed("category.description")
|
||||||
|
description(description) {
|
||||||
|
return `${description.substr(0, 200)}${description.length > 200 ? '…' : ''}`;
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,40 @@
|
||||||
|
import MultiSelectComponent from "select-kit/components/multi-select";
|
||||||
|
import Category from "discourse/models/category";
|
||||||
|
|
||||||
|
export default MultiSelectComponent.extend({
|
||||||
|
pluginApiIdentifiers: ["category-selector"],
|
||||||
|
classNames: "category-selector",
|
||||||
|
filterable: true,
|
||||||
|
allowAny: false,
|
||||||
|
rowComponent: "category-row",
|
||||||
|
|
||||||
|
init() {
|
||||||
|
this._super();
|
||||||
|
|
||||||
|
this.set("headerComponentOptions", Ember.Object.create({
|
||||||
|
selectedNameComponent: "multi-select/selected-category"
|
||||||
|
}));
|
||||||
|
|
||||||
|
this.set("rowComponentOptions", Ember.Object.create({
|
||||||
|
displayCategoryDescription: false
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
|
||||||
|
computeValues() {
|
||||||
|
return Ember.makeArray(this.get("categories")).map(c => c.id);
|
||||||
|
},
|
||||||
|
|
||||||
|
mutateValues(values) {
|
||||||
|
this.set("categories", values.map(v => Category.findById(v)));
|
||||||
|
},
|
||||||
|
|
||||||
|
filterComputedContent(computedContent, computedValues, filter) {
|
||||||
|
const regex = new RegExp(filter.toLowerCase(), 'i');
|
||||||
|
return computedContent.filter(category => Ember.get(category, "name").match(regex));
|
||||||
|
},
|
||||||
|
|
||||||
|
computeContent() {
|
||||||
|
const blacklist = Ember.makeArray(this.get("blacklist"));
|
||||||
|
return Category.list().filter(category => !blacklist.includes(category));
|
||||||
|
}
|
||||||
|
});
|
|
@ -1,7 +1,8 @@
|
||||||
import SelectBoxKitComponent from "select-box-kit/components/select-box-kit";
|
import SingleSelectComponent from "select-kit/components/single-select";
|
||||||
import { on } from "ember-addons/ember-computed-decorators";
|
import { on } from "ember-addons/ember-computed-decorators";
|
||||||
|
|
||||||
export default SelectBoxKitComponent.extend({
|
export default SingleSelectComponent.extend({
|
||||||
|
pluginApiIdentifiers: ["combo-box"],
|
||||||
classNames: "combobox combo-box",
|
classNames: "combobox combo-box",
|
||||||
autoFilterable: true,
|
autoFilterable: true,
|
||||||
headerComponent: "combo-box/combo-box-header",
|
headerComponent: "combo-box/combo-box-header",
|
||||||
|
@ -10,6 +11,12 @@ export default SelectBoxKitComponent.extend({
|
||||||
caretDownIcon: "caret-down",
|
caretDownIcon: "caret-down",
|
||||||
clearable: false,
|
clearable: false,
|
||||||
|
|
||||||
|
computeHeaderContent() {
|
||||||
|
let content = this.baseHeaderComputedContent();
|
||||||
|
content.hasSelection = this.get("hasSelection");
|
||||||
|
return content;
|
||||||
|
},
|
||||||
|
|
||||||
@on("didReceiveAttrs")
|
@on("didReceiveAttrs")
|
||||||
_setComboBoxOptions() {
|
_setComboBoxOptions() {
|
||||||
this.get("headerComponentOptions").setProperties({
|
this.get("headerComponentOptions").setProperties({
|
|
@ -0,0 +1,21 @@
|
||||||
|
import SelectKitHeaderComponent from "select-kit/components/select-kit/select-kit-header";
|
||||||
|
import { default as computed } from "ember-addons/ember-computed-decorators";
|
||||||
|
|
||||||
|
export default SelectKitHeaderComponent.extend({
|
||||||
|
layoutName: "select-kit/templates/components/combo-box/combo-box-header",
|
||||||
|
classNames: "combo-box-header",
|
||||||
|
|
||||||
|
clearable: Ember.computed.alias("options.clearable"),
|
||||||
|
caretUpIcon: Ember.computed.alias("options.caretUpIcon"),
|
||||||
|
caretDownIcon: Ember.computed.alias("options.caretDownIcon"),
|
||||||
|
|
||||||
|
@computed("isExpanded", "caretUpIcon", "caretDownIcon")
|
||||||
|
caretIcon(isExpanded, caretUpIcon, caretDownIcon) {
|
||||||
|
return isExpanded === true ? caretUpIcon : caretDownIcon;
|
||||||
|
},
|
||||||
|
|
||||||
|
@computed("clearable", "computedContent.hasSelection")
|
||||||
|
shouldDisplayClearableButton(clearable, hasSelection) {
|
||||||
|
return clearable === true && hasSelection === true;
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,32 @@
|
||||||
|
import SingleSelectComponent from "select-kit/components/single-select";
|
||||||
|
import { on } from "ember-addons/ember-computed-decorators";
|
||||||
|
|
||||||
|
export default SingleSelectComponent.extend({
|
||||||
|
pluginApiIdentifiers: ["dropdown-select-box"],
|
||||||
|
classNames: "dropdown-select-box",
|
||||||
|
verticalOffset: 3,
|
||||||
|
fullWidthOnMobile: true,
|
||||||
|
filterable: false,
|
||||||
|
autoFilterable: false,
|
||||||
|
headerComponent: "dropdown-select-box/dropdown-select-box-header",
|
||||||
|
rowComponent: "dropdown-select-box/dropdown-select-box-row",
|
||||||
|
showFullTitle: true,
|
||||||
|
allowInitialValueMutation: false,
|
||||||
|
|
||||||
|
@on("didReceiveAttrs")
|
||||||
|
_setDropdownSelectBoxComponentOptions() {
|
||||||
|
this.get("headerComponentOptions").setProperties({
|
||||||
|
showFullTitle: this.get("showFullTitle")
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
didClickOutside() {
|
||||||
|
if (this.get("isExpanded") === false) { return; }
|
||||||
|
this.close();
|
||||||
|
},
|
||||||
|
|
||||||
|
didSelect() {
|
||||||
|
this._super();
|
||||||
|
this.close();
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,15 @@
|
||||||
|
import SelectKitHeaderComponent from "select-kit/components/select-kit/select-kit-header";
|
||||||
|
import computed from "ember-addons/ember-computed-decorators";
|
||||||
|
|
||||||
|
export default SelectKitHeaderComponent.extend({
|
||||||
|
layoutName: "select-kit/templates/components/dropdown-select-box/dropdown-select-box-header",
|
||||||
|
classNames: "dropdown-select-box-header",
|
||||||
|
tagName: "button",
|
||||||
|
|
||||||
|
classNameBindings: ["btnClassName"],
|
||||||
|
|
||||||
|
@computed("options.showFullTitle")
|
||||||
|
btnClassName(showFullTitle) {
|
||||||
|
return `btn ${showFullTitle ? 'btn-icon-text' : 'no-text btn-icon'}`;
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,9 @@
|
||||||
|
import SelectKitRowComponent from "select-kit/components/select-kit/select-kit-row";
|
||||||
|
|
||||||
|
export default SelectKitRowComponent.extend({
|
||||||
|
layoutName: "select-kit/templates/components/dropdown-select-box/dropdown-select-box-row",
|
||||||
|
classNames: "dropdown-select-box-row",
|
||||||
|
|
||||||
|
name: Ember.computed.alias("computedContent.name"),
|
||||||
|
description: Ember.computed.alias("computedContent.originalContent.description")
|
||||||
|
});
|
|
@ -1,7 +1,6 @@
|
||||||
import { default as computed, observes } from "ember-addons/ember-computed-decorators";
|
import ComboBoxComponent from "select-kit/components/combo-box";
|
||||||
import ComboBoxComponent from "select-box-kit/components/combo-box";
|
|
||||||
import { CLOSE_STATUS_TYPE } from "discourse/controllers/edit-topic-timer";
|
import { CLOSE_STATUS_TYPE } from "discourse/controllers/edit-topic-timer";
|
||||||
import DatetimeMixin from "select-box-kit/components/future-date-input-selector/mixin";
|
import DatetimeMixin from "select-kit/components/future-date-input-selector/mixin";
|
||||||
|
|
||||||
const TIMEFRAME_BASE = {
|
const TIMEFRAME_BASE = {
|
||||||
enabled: () => true,
|
enabled: () => true,
|
||||||
|
@ -112,14 +111,30 @@ export function timeframeDetails(id) {
|
||||||
export const FORMAT = "YYYY-MM-DD HH:mm";
|
export const FORMAT = "YYYY-MM-DD HH:mm";
|
||||||
|
|
||||||
export default ComboBoxComponent.extend(DatetimeMixin, {
|
export default ComboBoxComponent.extend(DatetimeMixin, {
|
||||||
|
pluginApiIdentifiers: ["future-date-input-selector"],
|
||||||
classNames: ["future-date-input-selector"],
|
classNames: ["future-date-input-selector"],
|
||||||
isCustom: Ember.computed.equal("value", "pick_date_and_time"),
|
isCustom: Ember.computed.equal("value", "pick_date_and_time"),
|
||||||
clearable: true,
|
clearable: true,
|
||||||
rowComponent: "future-date-input-selector/future-date-input-selector-row",
|
rowComponent: "future-date-input-selector/future-date-input-selector-row",
|
||||||
headerComponent: "future-date-input-selector/future-date-input-selector-header",
|
headerComponent: "future-date-input-selector/future-date-input-selector-header",
|
||||||
|
|
||||||
@computed
|
computeHeaderContent() {
|
||||||
content() {
|
let content = this.baseHeaderComputedContent();
|
||||||
|
content.datetime = this._computeDatetimeForValue(this.get("computedValue"));
|
||||||
|
content.name = this.get("selectedComputedContent.name") || content.name;
|
||||||
|
content.hasSelection = this.get("hasSelection");
|
||||||
|
content.icons = this._computeIconsForValue(this.get("computedValue"));
|
||||||
|
return content;
|
||||||
|
},
|
||||||
|
|
||||||
|
computeContentItem(contentItem, name) {
|
||||||
|
let item = this.baseComputedContentItem(contentItem, name);
|
||||||
|
item.datetime = this._computeDatetimeForValue(contentItem.id);
|
||||||
|
item.icons = this._computeIconsForValue(contentItem.id);
|
||||||
|
return item;
|
||||||
|
},
|
||||||
|
|
||||||
|
computeContent() {
|
||||||
let now = moment();
|
let now = moment();
|
||||||
let opts = {
|
let opts = {
|
||||||
now,
|
now,
|
||||||
|
@ -138,21 +153,15 @@ export default ComboBoxComponent.extend(DatetimeMixin, {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
@observes("value")
|
mutateValue(value) {
|
||||||
_updateInput() {
|
|
||||||
if (this.get("isCustom")) return;
|
if (this.get("isCustom")) return;
|
||||||
let input = null;
|
let input = null;
|
||||||
const { time } = this.get("updateAt");
|
const { time } = this._updateAt(value);
|
||||||
|
|
||||||
if (time && !Ember.isEmpty(this.get("value"))) {
|
if (time && !Ember.isEmpty(value)) {
|
||||||
input = time.format(FORMAT);
|
input = time.format(FORMAT);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.set("input", input);
|
this.setProperties({ input, value });
|
||||||
},
|
},
|
||||||
|
|
||||||
@computed("value")
|
|
||||||
updateAt(value) {
|
|
||||||
return this._updateAt(value);
|
|
||||||
}
|
|
||||||
});
|
});
|
|
@ -0,0 +1,6 @@
|
||||||
|
import ComboBoxHeaderComponent from "select-kit/components/combo-box/combo-box-header";
|
||||||
|
|
||||||
|
export default ComboBoxHeaderComponent.extend({
|
||||||
|
layoutName: "select-kit/templates/components/future-date-input-selector/future-date-input-selector-header",
|
||||||
|
classNames: "future-date-input-selector-header"
|
||||||
|
});
|
|
@ -0,0 +1,6 @@
|
||||||
|
import SelectKitRowComponent from "select-kit/components/select-kit/select-kit-row";
|
||||||
|
|
||||||
|
export default SelectKitRowComponent.extend({
|
||||||
|
layoutName: "select-kit/templates/components/future-date-input-selector/future-date-input-selector-row",
|
||||||
|
classNames: "future-date-input-selector-row"
|
||||||
|
});
|
|
@ -1,16 +1,15 @@
|
||||||
import { iconHTML } from 'discourse-common/lib/icon-library';
|
|
||||||
import { CLOSE_STATUS_TYPE } from 'discourse/controllers/edit-topic-timer';
|
import { CLOSE_STATUS_TYPE } from 'discourse/controllers/edit-topic-timer';
|
||||||
import { timeframeDetails } from 'select-box-kit/components/future-date-input-selector';
|
import { timeframeDetails } from 'select-kit/components/future-date-input-selector';
|
||||||
|
|
||||||
export default Ember.Mixin.create({
|
export default Ember.Mixin.create({
|
||||||
_computeIconForValue(value) {
|
_computeIconsForValue(value) {
|
||||||
let {icon} = this._updateAt(value);
|
let {icon} = this._updateAt(value);
|
||||||
|
|
||||||
if (icon) {
|
if (icon) {
|
||||||
return icon.split(",").map(i => iconHTML(i)).join(" ");
|
return icon.split(",");
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return [];
|
||||||
},
|
},
|
||||||
|
|
||||||
_computeDatetimeForValue(value) {
|
_computeDatetimeForValue(value) {
|
||||||
|
@ -20,7 +19,6 @@ export default Ember.Mixin.create({
|
||||||
|
|
||||||
let {time} = this._updateAt(value);
|
let {time} = this._updateAt(value);
|
||||||
if (time) {
|
if (time) {
|
||||||
|
|
||||||
let details = timeframeDetails(value);
|
let details = timeframeDetails(value);
|
||||||
if (!details.displayWhen) {
|
if (!details.displayWhen) {
|
||||||
time = null;
|
time = null;
|
||||||
|
@ -34,6 +32,7 @@ export default Ember.Mixin.create({
|
||||||
|
|
||||||
_updateAt(selection) {
|
_updateAt(selection) {
|
||||||
let details = timeframeDetails(selection);
|
let details = timeframeDetails(selection);
|
||||||
|
|
||||||
if (details) {
|
if (details) {
|
||||||
return {
|
return {
|
||||||
time: details.when(moment(), this.get('statusType') !== CLOSE_STATUS_TYPE ? 8 : 18),
|
time: details.when(moment(), this.get('statusType') !== CLOSE_STATUS_TYPE ? 8 : 18),
|
|
@ -1,11 +1,12 @@
|
||||||
import NotificationOptionsComponent from "select-box-kit/components/notifications-button";
|
import NotificationOptionsComponent from "select-kit/components/notifications-button";
|
||||||
|
|
||||||
export default NotificationOptionsComponent.extend({
|
export default NotificationOptionsComponent.extend({
|
||||||
|
pluginApiIdentifiers: ["grouo-notifications-button"],
|
||||||
classNames: ["group-notifications-button"],
|
classNames: ["group-notifications-button"],
|
||||||
value: Ember.computed.alias("group.group_user.notification_level"),
|
|
||||||
i18nPrefix: "groups.notifications",
|
i18nPrefix: "groups.notifications",
|
||||||
|
allowInitialValueMutation: false,
|
||||||
|
|
||||||
selectValueFunction(value) {
|
mutateValue(value) {
|
||||||
this.get("group").setNotification(value, this.get("user.id"));
|
this.get("group").setNotification(value, this.get("user.id"));
|
||||||
}
|
}
|
||||||
});
|
});
|
|
@ -0,0 +1,54 @@
|
||||||
|
import MultiSelectComponent from "select-kit/components/multi-select";
|
||||||
|
|
||||||
|
export default MultiSelectComponent.extend({
|
||||||
|
pluginApiIdentifiers: ["list-setting"],
|
||||||
|
classNames: "list-setting",
|
||||||
|
tokenSeparator: "|",
|
||||||
|
settingValue: "",
|
||||||
|
choices: null,
|
||||||
|
filterable: true,
|
||||||
|
|
||||||
|
init() {
|
||||||
|
this._super();
|
||||||
|
|
||||||
|
if (!Ember.isNone(this.get("settingName"))) {
|
||||||
|
this.set("nameProperty", this.get("settingName"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.get("nameProperty").indexOf("color") > -1) {
|
||||||
|
this.set("headerComponentOptions", Ember.Object.create({
|
||||||
|
selectedNameComponent: "multi-select/selected-color"
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
computeContent() {
|
||||||
|
let content;
|
||||||
|
if (Ember.isNone(this.get("choices"))) {
|
||||||
|
content = this.get("settingValue").split(this.get("tokenSeparator"));;
|
||||||
|
} else {
|
||||||
|
content = this.get("choices");
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ember.makeArray(content).filter(c => c);
|
||||||
|
},
|
||||||
|
|
||||||
|
mutateValues(values) {
|
||||||
|
this.set("settingValue", values.join(this.get("tokenSeparator")));
|
||||||
|
},
|
||||||
|
|
||||||
|
computeValues() {
|
||||||
|
return this.get("settingValue")
|
||||||
|
.split(this.get("tokenSeparator"))
|
||||||
|
.filter(c => c);
|
||||||
|
},
|
||||||
|
|
||||||
|
_handleTabOnKeyDown(event) {
|
||||||
|
if (this.$highlightedRow().length === 1) {
|
||||||
|
this._super(event);
|
||||||
|
} else {
|
||||||
|
this.close();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,255 @@
|
||||||
|
import SelectKitComponent from "select-kit/components/select-kit";
|
||||||
|
import computed from "ember-addons/ember-computed-decorators";
|
||||||
|
import { on } from "ember-addons/ember-computed-decorators";
|
||||||
|
const { get, isNone, isEmpty, makeArray } = Ember;
|
||||||
|
|
||||||
|
export default SelectKitComponent.extend({
|
||||||
|
pluginApiIdentifiers: ["multi-select"],
|
||||||
|
classNames: "multi-select",
|
||||||
|
headerComponent: "multi-select/multi-select-header",
|
||||||
|
filterComponent: null,
|
||||||
|
headerText: "select_kit.default_header_text",
|
||||||
|
allowAny: true,
|
||||||
|
allowInitialValueMutation: false,
|
||||||
|
autoFilterable: true,
|
||||||
|
selectedNameComponent: "multi-select/selected-name",
|
||||||
|
|
||||||
|
init() {
|
||||||
|
this._super();
|
||||||
|
|
||||||
|
this.set("computedValues", []);
|
||||||
|
if (isNone(this.get("values"))) { this.set("values", []); }
|
||||||
|
|
||||||
|
this.set("headerComponentOptions", Ember.Object.create({
|
||||||
|
selectedNameComponent: this.get("selectedNameComponent")
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
|
||||||
|
@on("didRender")
|
||||||
|
_setChoicesMaxWidth() {
|
||||||
|
const width = this.$body().outerWidth(false);
|
||||||
|
this.$(".choices").css({ maxWidth: width, width });
|
||||||
|
},
|
||||||
|
|
||||||
|
@on("didReceiveAttrs")
|
||||||
|
_compute() {
|
||||||
|
Ember.run.scheduleOnce("afterRender", () => {
|
||||||
|
this.willComputeAttributes();
|
||||||
|
let content = this._beforeWillComputeContent(this.get("content"));
|
||||||
|
content = this.willComputeContent(content);
|
||||||
|
let values = this._beforeWillComputeValues(this.get("values"));
|
||||||
|
content = this.computeContent(content);
|
||||||
|
content = this._beforeDidComputeContent(content);
|
||||||
|
values = this.willComputeValues(values);
|
||||||
|
values = this.computeValues(values);
|
||||||
|
values = this._beforeDidComputeValues(values);
|
||||||
|
this.set("headerComputedContent", this.computeHeaderContent());
|
||||||
|
this.didComputeContent(content);
|
||||||
|
this.didComputeValues(values);
|
||||||
|
this.didComputeAttributes();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
@computed("filter", "shouldDisplayCreateRow")
|
||||||
|
createRowComputedContent(filter, shouldDisplayCreateRow) {
|
||||||
|
if (shouldDisplayCreateRow === true) {
|
||||||
|
let content = this.createContentFromInput(filter);
|
||||||
|
return this.computeContentItem(content, { created: true });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
@computed("filter", "computedValues")
|
||||||
|
shouldDisplayCreateRow(filter, computedValues) {
|
||||||
|
return this._super() && !computedValues.includes(filter);
|
||||||
|
},
|
||||||
|
|
||||||
|
_beforeWillComputeValues(values) {
|
||||||
|
return values.map(v => this._castInteger(v === "" ? null : v));
|
||||||
|
},
|
||||||
|
willComputeValues(values) { return values; },
|
||||||
|
computeValues(values) { return values; },
|
||||||
|
_beforeDidComputeValues(values) {
|
||||||
|
this.setProperties({ computedValues: values });
|
||||||
|
return values;
|
||||||
|
},
|
||||||
|
didComputeValues(values) { return values; },
|
||||||
|
|
||||||
|
mutateAttributes() {
|
||||||
|
Ember.run.next(() => {
|
||||||
|
this.mutateContent(this.get("computedContent"));
|
||||||
|
this.mutateValues(this.get("computedValues"));
|
||||||
|
this.set("headerComputedContent", this.computeHeaderContent());
|
||||||
|
});
|
||||||
|
},
|
||||||
|
mutateValues(computedValues) { this.set("values", computedValues); },
|
||||||
|
|
||||||
|
filterComputedContent(computedContent, computedValues, filter) {
|
||||||
|
const lowerFilter = filter.toLowerCase();
|
||||||
|
return computedContent.filter(c => {
|
||||||
|
return get(c, "name").toLowerCase().indexOf(lowerFilter) > -1;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
@computed("computedContent.[]", "computedValues.[]", "filter")
|
||||||
|
filteredComputedContent(computedContent, computedValues, filter) {
|
||||||
|
computedContent = computedContent.filter(c => {
|
||||||
|
return !computedValues.includes(get(c, "value"));
|
||||||
|
});
|
||||||
|
|
||||||
|
if (this.get("shouldFilter") === true) {
|
||||||
|
computedContent = this.filterComputedContent(computedContent, computedValues, filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
return computedContent.slice(0, this.get("limitMatches"));
|
||||||
|
},
|
||||||
|
|
||||||
|
baseHeaderComputedContent() {
|
||||||
|
return {
|
||||||
|
selectedComputedContents: this.get("selectedComputedContents")
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
@computed("filter")
|
||||||
|
templateForCreateRow() {
|
||||||
|
return (rowComponent) => {
|
||||||
|
return I18n.t("select_kit.create", { content: rowComponent.get("computedContent.name")});
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
didPressBackspace(event) {
|
||||||
|
this.expand();
|
||||||
|
this.keyDown(event);
|
||||||
|
this._destroyEvent(event);
|
||||||
|
},
|
||||||
|
|
||||||
|
didPressEscape(event) {
|
||||||
|
const $highlighted = this.$(".selected-name.is-highlighted");
|
||||||
|
if ($highlighted.length > 0) {
|
||||||
|
$highlighted.removeClass("is-highlighted");
|
||||||
|
}
|
||||||
|
|
||||||
|
this._super(event);
|
||||||
|
},
|
||||||
|
|
||||||
|
keyDown(event) {
|
||||||
|
if (!isEmpty(this.get("filter"))) return;
|
||||||
|
|
||||||
|
const keyCode = event.keyCode || event.which;
|
||||||
|
const $filterInput = this.$filterInput();
|
||||||
|
|
||||||
|
// select all choices
|
||||||
|
if (this.get("hasSelection") && event.metaKey === true && keyCode === 65) {
|
||||||
|
this.$(".choices .selected-name:not(.is-locked)").addClass("is-highlighted");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// clear selection when multiple
|
||||||
|
if (this.$(".selected-name.is-highlighted").length >= 1 && keyCode === this.keys.BACKSPACE) {
|
||||||
|
const highlightedComputedContents = [];
|
||||||
|
$.each(this.$(".selected-name.is-highlighted"), (i, el) => {
|
||||||
|
const computedContent = this._findComputedContentItemByGuid($(el).attr("data-guid"));
|
||||||
|
if (!Ember.isNone(computedContent)) { highlightedComputedContents.push(computedContent); }
|
||||||
|
});
|
||||||
|
this.send("onDeselect", highlightedComputedContents);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// try to remove last item from the list
|
||||||
|
if (keyCode === this.keys.BACKSPACE) {
|
||||||
|
let $lastSelectedValue = $(this.$(".choices .selected-name:not(.is-locked)").last());
|
||||||
|
|
||||||
|
if ($lastSelectedValue.length === 0) { return; }
|
||||||
|
|
||||||
|
if ($filterInput.not(":visible") && $lastSelectedValue.length > 0) {
|
||||||
|
$lastSelectedValue.click();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($filterInput.val() === "") {
|
||||||
|
if ($filterInput.is(":focus")) {
|
||||||
|
if ($lastSelectedValue.length > 0) { $lastSelectedValue.click(); }
|
||||||
|
} else {
|
||||||
|
if ($lastSelectedValue.length > 0) {
|
||||||
|
$lastSelectedValue.click();
|
||||||
|
} else {
|
||||||
|
$filterInput.focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
@computed("computedValues.[]", "computedContent.[]")
|
||||||
|
selectedComputedContents(computedValues, computedContent) {
|
||||||
|
const selected = [];
|
||||||
|
computedValues.forEach(v => selected.push(computedContent.findBy("value", v)) );
|
||||||
|
return selected;
|
||||||
|
},
|
||||||
|
|
||||||
|
@computed("selectedComputedContents.[]")
|
||||||
|
hasSelection(selectedComputedContents) { return !Ember.isEmpty(selectedComputedContents); },
|
||||||
|
|
||||||
|
autoHighlight() {
|
||||||
|
Ember.run.schedule("afterRender", () => {
|
||||||
|
if (this.get("isExpanded") === false) { return; }
|
||||||
|
if (this.get("renderedBodyOnce") === false) { return; }
|
||||||
|
if (!isNone(this.get("highlightedValue"))) { return; }
|
||||||
|
|
||||||
|
if (isEmpty(this.get("filteredComputedContent"))) {
|
||||||
|
if (this.get("createRowComputedContent")) {
|
||||||
|
this.send("onHighlight", this.get("createRowComputedContent"));
|
||||||
|
} else if (this.get("noneRowComputedContent") && this.get("hasSelection") === true) {
|
||||||
|
this.send("onHighlight", this.get("noneRowComputedContent"));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.send("onHighlight", this.get("filteredComputedContent.firstObject"));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
didSelect() {
|
||||||
|
this.focus();
|
||||||
|
this.autoHighlight();
|
||||||
|
},
|
||||||
|
|
||||||
|
didDeselect() {
|
||||||
|
this.focus();
|
||||||
|
this.autoHighlight();
|
||||||
|
},
|
||||||
|
|
||||||
|
validateComputedContentItem(computedContentItem) {
|
||||||
|
return !this.get("computedValues").includes(computedContentItem.value);
|
||||||
|
},
|
||||||
|
|
||||||
|
actions: {
|
||||||
|
onClear() {
|
||||||
|
this.get("selectedComputedContents").forEach(selectedComputedContent => {
|
||||||
|
this.send("onDeselect", selectedComputedContent);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
onCreate(computedContentItem) {
|
||||||
|
if (this.validateComputedContentItem(computedContentItem)) {
|
||||||
|
this.get("computedContent").pushObject(computedContentItem);
|
||||||
|
this.send("onSelect", computedContentItem);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
onSelect(computedContentItem) {
|
||||||
|
this.willSelect(computedContentItem);
|
||||||
|
this.get("computedValues").pushObject(computedContentItem.value);
|
||||||
|
Ember.run.next(() => this.mutateAttributes());
|
||||||
|
Ember.run.schedule("afterRender", () => this.didSelect(computedContentItem));
|
||||||
|
},
|
||||||
|
|
||||||
|
onDeselect(rowComputedContentItems) {
|
||||||
|
rowComputedContentItems = Ember.makeArray(rowComputedContentItems);
|
||||||
|
const generatedComputedContents = this._filterRemovableComputedContents(makeArray(rowComputedContentItems));
|
||||||
|
this.willDeselect(rowComputedContentItems);
|
||||||
|
this.get("computedValues").removeObjects(rowComputedContentItems.map(r => r.value));
|
||||||
|
this.get("computedContent").removeObjects(generatedComputedContents);
|
||||||
|
Ember.run.next(() => this.mutateAttributes());
|
||||||
|
Ember.run.schedule("afterRender", () => this.didDeselect(rowComputedContentItems));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
|
@ -1,11 +1,11 @@
|
||||||
import { on } from "ember-addons/ember-computed-decorators";
|
import { on } from "ember-addons/ember-computed-decorators";
|
||||||
import computed from "ember-addons/ember-computed-decorators";
|
import computed from "ember-addons/ember-computed-decorators";
|
||||||
import SelectBoxKitHeaderComponent from "select-box-kit/components/select-box-kit/select-box-kit-header";
|
import SelectKitHeaderComponent from "select-kit/components/select-kit/select-kit-header";
|
||||||
|
|
||||||
export default SelectBoxKitHeaderComponent.extend({
|
export default SelectKitHeaderComponent.extend({
|
||||||
attributeBindings: ["names:data-name"],
|
attributeBindings: ["names:data-name"],
|
||||||
classNames: "multi-combo-box-header",
|
classNames: "multi-select-header",
|
||||||
layoutName: "select-box-kit/templates/components/multi-combo-box/multi-combo-box-header",
|
layoutName: "select-kit/templates/components/multi-select/multi-select-header",
|
||||||
selectedNameComponent: Ember.computed.alias("options.selectedNameComponent"),
|
selectedNameComponent: Ember.computed.alias("options.selectedNameComponent"),
|
||||||
|
|
||||||
@on("didRender")
|
@on("didRender")
|
||||||
|
@ -25,6 +25,8 @@ export default SelectBoxKitHeaderComponent.extend({
|
||||||
$filter.width(availableSpace - parentRightPadding * 4);
|
$filter.width(availableSpace - parentRightPadding * 4);
|
||||||
},
|
},
|
||||||
|
|
||||||
@computed("selectedContent.[]")
|
@computed("computedContent.selectedComputedContents.[]")
|
||||||
names(selectedContent) { return selectedContent.map(sc => sc.name).join(","); }
|
names(selectedComputedContents) {
|
||||||
|
return Ember.makeArray(selectedComputedContents).map(sc => sc.name).join(",");
|
||||||
|
}
|
||||||
});
|
});
|
|
@ -0,0 +1,13 @@
|
||||||
|
import SelectedNameComponent from "select-kit/components/multi-select/selected-name";
|
||||||
|
import computed from "ember-addons/ember-computed-decorators";
|
||||||
|
import { categoryBadgeHTML } from "discourse/helpers/category-link";
|
||||||
|
|
||||||
|
export default SelectedNameComponent.extend({
|
||||||
|
classNames: "selected-category",
|
||||||
|
layoutName: "select-kit/templates/components/multi-select/selected-category",
|
||||||
|
|
||||||
|
@computed("content.originalContent")
|
||||||
|
badge(category) {
|
||||||
|
return categoryBadgeHTML(category, {allowUncategorized: true, link: false}).htmlSafe();
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,11 @@
|
||||||
|
import SelectedNameComponent from "select-kit/components/multi-select/selected-name";
|
||||||
|
|
||||||
|
export default SelectedNameComponent.extend({
|
||||||
|
classNames: "selected-color",
|
||||||
|
layoutName: "select-kit/templates/components/multi-select/selected-color",
|
||||||
|
|
||||||
|
didRender() {
|
||||||
|
const name = this.get("content.name");
|
||||||
|
this.$(".color-preview").css("background", `#${name}`.htmlSafe());
|
||||||
|
}
|
||||||
|
});
|
|
@ -1,18 +1,27 @@
|
||||||
|
import computed from "ember-addons/ember-computed-decorators";
|
||||||
|
|
||||||
export default Ember.Component.extend({
|
export default Ember.Component.extend({
|
||||||
attributeBindings: ["tabindex","content.name:data-name", "content.value:data-value"],
|
attributeBindings: [
|
||||||
classNames: "selected-name",
|
"tabindex",
|
||||||
|
"content.name:data-name",
|
||||||
|
"content.value:data-value",
|
||||||
|
"guid:data-guid"
|
||||||
|
],
|
||||||
|
classNames: ["selected-name", "choice"],
|
||||||
classNameBindings: ["isHighlighted", "isLocked"],
|
classNameBindings: ["isHighlighted", "isLocked"],
|
||||||
layoutName: "select-box-kit/templates/components/multi-combo-box/selected-name",
|
layoutName: "select-kit/templates/components/multi-select/selected-name",
|
||||||
tagName: "li",
|
tagName: "li",
|
||||||
tabindex: -1,
|
tabindex: -1,
|
||||||
|
|
||||||
|
@computed("content")
|
||||||
|
guid(content) { return Ember.guidFor(content); },
|
||||||
|
|
||||||
isLocked: Ember.computed("content.locked", function() {
|
isLocked: Ember.computed("content.locked", function() {
|
||||||
return this.getWithDefault("content.locked", false);
|
return this.getWithDefault("content.locked", false);
|
||||||
}),
|
}),
|
||||||
|
|
||||||
click() {
|
click() {
|
||||||
if (this.get("isLocked") === true) { return false; }
|
if (this.get("isLocked") === true) { return false; }
|
||||||
|
|
||||||
this.toggleProperty("isHighlighted");
|
this.toggleProperty("isHighlighted");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
import CategoryRowComponent from "select-kit/components/category-row";
|
||||||
|
|
||||||
|
export default CategoryRowComponent.extend({
|
||||||
|
layoutName: "select-kit/templates/components/category-row",
|
||||||
|
classNames: "none category-row",
|
||||||
|
|
||||||
|
click() {
|
||||||
|
this.sendAction("onClear");
|
||||||
|
}
|
||||||
|
});
|
|
@ -1,4 +1,4 @@
|
||||||
import DropdownSelectBoxComponent from "select-box-kit/components/dropdown-select-box";
|
import DropdownSelectBoxComponent from "select-kit/components/dropdown-select-box";
|
||||||
import { default as computed, on } from "ember-addons/ember-computed-decorators";
|
import { default as computed, on } from "ember-addons/ember-computed-decorators";
|
||||||
import { buttonDetails } from "discourse/lib/notification-levels";
|
import { buttonDetails } from "discourse/lib/notification-levels";
|
||||||
import { allLevels } from "discourse/lib/notification-levels";
|
import { allLevels } from "discourse/lib/notification-levels";
|
||||||
|
@ -9,24 +9,29 @@ export default DropdownSelectBoxComponent.extend({
|
||||||
fullWidthOnMobile: true,
|
fullWidthOnMobile: true,
|
||||||
content: allLevels,
|
content: allLevels,
|
||||||
collectionHeight: "auto",
|
collectionHeight: "auto",
|
||||||
value: Ember.computed.alias("notificationLevel"),
|
|
||||||
castInteger: true,
|
castInteger: true,
|
||||||
autofilterable: false,
|
autofilterable: false,
|
||||||
filterable: false,
|
filterable: false,
|
||||||
rowComponent: "notifications-button/notifications-button-row",
|
rowComponent: "notifications-button/notifications-button-row",
|
||||||
headerComponent: "notifications-button/notifications-button-header",
|
allowInitialValueMutation: false,
|
||||||
|
|
||||||
i18nPrefix: "",
|
i18nPrefix: "",
|
||||||
i18nPostfix: "",
|
i18nPostfix: "",
|
||||||
showFullTitle: true,
|
|
||||||
|
|
||||||
@on("didReceiveAttrs", "didUpdateAttrs")
|
@computed("iconForSelectedDetails")
|
||||||
_setComponentOptions() {
|
headerIcon(iconForSelectedDetails) { return iconForSelectedDetails; },
|
||||||
this.get("headerComponentOptions").setProperties({
|
|
||||||
i18nPrefix: this.get("i18nPrefix"),
|
|
||||||
showFullTitle: this.get("showFullTitle"),
|
|
||||||
});
|
|
||||||
|
|
||||||
|
@computed("selectedDetails.icon")
|
||||||
|
iconForSelectedDetails(icon) { return icon; },
|
||||||
|
|
||||||
|
computeHeaderContent() {
|
||||||
|
let content = this.baseHeaderComputedContent();
|
||||||
|
content.name = I18n.t(`${this.get("i18nPrefix")}.${this.get("selectedDetails.key")}.title`);
|
||||||
|
content.hasSelection = this.get("hasSelection");
|
||||||
|
return content;
|
||||||
|
},
|
||||||
|
|
||||||
|
@on("didReceiveAttrs")
|
||||||
|
_setNotificationsButtonComponentOptions() {
|
||||||
this.get("rowComponentOptions").setProperties({
|
this.get("rowComponentOptions").setProperties({
|
||||||
i18nPrefix: this.get("i18nPrefix"),
|
i18nPrefix: this.get("i18nPrefix"),
|
||||||
i18nPostfix: this.get("i18nPostfix")
|
i18nPostfix: this.get("i18nPostfix")
|
|
@ -1,4 +1,4 @@
|
||||||
import DropdownSelectBoxRoxComponent from "select-box-kit/components/dropdown-select-box/dropdown-select-box-row";
|
import DropdownSelectBoxRoxComponent from "select-kit/components/dropdown-select-box/dropdown-select-box-row";
|
||||||
import { buttonDetails } from "discourse/lib/notification-levels";
|
import { buttonDetails } from "discourse/lib/notification-levels";
|
||||||
import computed from "ember-addons/ember-computed-decorators";
|
import computed from "ember-addons/ember-computed-decorators";
|
||||||
import { iconHTML } from 'discourse-common/lib/icon-library';
|
import { iconHTML } from 'discourse-common/lib/icon-library';
|
||||||
|
@ -9,13 +9,13 @@ export default DropdownSelectBoxRoxComponent.extend({
|
||||||
i18nPrefix: Ember.computed.alias("options.i18nPrefix"),
|
i18nPrefix: Ember.computed.alias("options.i18nPrefix"),
|
||||||
i18nPostfix: Ember.computed.alias("options.i18nPostfix"),
|
i18nPostfix: Ember.computed.alias("options.i18nPostfix"),
|
||||||
|
|
||||||
@computed("content.value", "i18nPrefix")
|
@computed("computedContent.value", "i18nPrefix")
|
||||||
title(value, prefix) {
|
title(value, prefix) {
|
||||||
const key = buttonDetails(value).key;
|
const key = buttonDetails(value).key;
|
||||||
return I18n.t(`${prefix}.${key}.title`);
|
return I18n.t(`${prefix}.${key}.title`);
|
||||||
},
|
},
|
||||||
|
|
||||||
@computed("content.name", "content.originalContent.icon")
|
@computed("computedContent.name", "computedContent.originalContent.icon")
|
||||||
icon(contentName, icon) {
|
icon(contentName, icon) {
|
||||||
return iconHTML(icon, { class: contentName.dasherize() });
|
return iconHTML(icon, { class: contentName.dasherize() });
|
||||||
},
|
},
|
||||||
|
@ -30,7 +30,7 @@ export default DropdownSelectBoxRoxComponent.extend({
|
||||||
return Handlebars.escapeExpression(I18n.t(`${_start}.title`));
|
return Handlebars.escapeExpression(I18n.t(`${_start}.title`));
|
||||||
},
|
},
|
||||||
|
|
||||||
@computed("i18nPrefix", "i18nPostfix", "content.name")
|
@computed("i18nPrefix", "i18nPostfix", "computedContent.name")
|
||||||
_start(prefix, postfix, contentName) {
|
_start(prefix, postfix, contentName) {
|
||||||
return `${prefix}.${contentName}${postfix}`;
|
return `${prefix}.${contentName}${postfix}`;
|
||||||
},
|
},
|
|
@ -1,12 +1,13 @@
|
||||||
import computed from "ember-addons/ember-computed-decorators";
|
import computed from "ember-addons/ember-computed-decorators";
|
||||||
|
|
||||||
export default Ember.Component.extend({
|
export default Ember.Component.extend({
|
||||||
|
pluginApiIdentifiers: ["pinned-button"],
|
||||||
descriptionKey: "help",
|
descriptionKey: "help",
|
||||||
classNames: "pinned-button",
|
classNames: "pinned-button",
|
||||||
classNameBindings: ["isHidden"],
|
classNameBindings: ["isHidden"],
|
||||||
layoutName: "select-box-kit/templates/components/pinned-button",
|
layoutName: "select-kit/templates/components/pinned-button",
|
||||||
|
|
||||||
@computed("topic.pinned_globally", "topic.pinned")
|
@computed("topic.pinned_globally", "pinned")
|
||||||
reasonText(pinnedGlobally, pinned) {
|
reasonText(pinnedGlobally, pinned) {
|
||||||
const globally = pinnedGlobally ? "_globally" : "";
|
const globally = pinnedGlobally ? "_globally" : "";
|
||||||
const pinnedKey = pinned ? `pinned${globally}` : "unpinned";
|
const pinnedKey = pinned ? `pinned${globally}` : "unpinned";
|
||||||
|
@ -14,7 +15,7 @@ export default Ember.Component.extend({
|
||||||
return I18n.t(key);
|
return I18n.t(key);
|
||||||
},
|
},
|
||||||
|
|
||||||
@computed("topic.pinned", "topic.deleted", "topic.unpinned")
|
@computed("pinned", "topic.deleted", "topic.unpinned")
|
||||||
isHidden(pinned, deleted, unpinned) {
|
isHidden(pinned, deleted, unpinned) {
|
||||||
return deleted || (!pinned && !unpinned);
|
return deleted || (!pinned && !unpinned);
|
||||||
}
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
import DropdownSelectBoxComponent from "select-kit/components/dropdown-select-box";
|
||||||
|
import { on } from "ember-addons/ember-computed-decorators";
|
||||||
|
import { iconHTML } from 'discourse-common/lib/icon-library';
|
||||||
|
|
||||||
|
export default DropdownSelectBoxComponent.extend({
|
||||||
|
pluginApiIdentifiers: ["pinned-options"],
|
||||||
|
classNames: "pinned-options",
|
||||||
|
allowInitialValueMutation: false,
|
||||||
|
|
||||||
|
autoHighlight() {},
|
||||||
|
|
||||||
|
computeHeaderContent() {
|
||||||
|
let content = this.baseHeaderComputedContent();
|
||||||
|
const pinnedGlobally = this.get("topic.pinned_globally");
|
||||||
|
const pinned = this.get("computedValue");
|
||||||
|
const globally = pinnedGlobally ? "_globally" : "";
|
||||||
|
const state = pinned ? `pinned${globally}` : "unpinned";
|
||||||
|
const title = I18n.t(`topic_statuses.${state}.title`);
|
||||||
|
|
||||||
|
content.name = `${title}${iconHTML("caret-down")}`.htmlSafe();
|
||||||
|
content.dataName = title;
|
||||||
|
content.icon = `thumb-tack ${state === "unpinned" ? "unpinned" : null}`;
|
||||||
|
return content;
|
||||||
|
},
|
||||||
|
|
||||||
|
@on("init")
|
||||||
|
_setContent() {
|
||||||
|
const globally = this.get("topic.pinned_globally") ? "_globally" : "";
|
||||||
|
|
||||||
|
this.set("content", [
|
||||||
|
{
|
||||||
|
id: "pinned",
|
||||||
|
name: I18n.t("topic_statuses.pinned" + globally + ".title"),
|
||||||
|
description: I18n.t('topic_statuses.pinned' + globally + '.help'),
|
||||||
|
icon: "thumb-tack"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "unpinned",
|
||||||
|
name: I18n.t("topic_statuses.unpinned.title"),
|
||||||
|
icon: "thumb-tack unpinned",
|
||||||
|
description: I18n.t('topic_statuses.unpinned.help'),
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
},
|
||||||
|
|
||||||
|
mutateValue(value) {
|
||||||
|
const topic = this.get("topic");
|
||||||
|
|
||||||
|
if (value === "unpinned") {
|
||||||
|
topic.clearPin();
|
||||||
|
} else {
|
||||||
|
topic.rePin();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,20 @@
|
||||||
|
import CategoryChooserComponent from "select-kit/components/category-chooser";
|
||||||
|
import Category from "discourse/models/category";
|
||||||
|
|
||||||
|
export default CategoryChooserComponent.extend({
|
||||||
|
pluginApiIdentifiers: ["advanced-search-category-chooser"],
|
||||||
|
rootNone: true,
|
||||||
|
rootNoneLabel: "category.all",
|
||||||
|
allowUncategorized: true,
|
||||||
|
clearable: true,
|
||||||
|
|
||||||
|
mutateValue(value) {
|
||||||
|
if (value) {
|
||||||
|
this.set("value", Category.findById(value));
|
||||||
|
} else {
|
||||||
|
this.set("value", null);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
computeValue(category) { if (category) return category.id; }
|
||||||
|
});
|
|
@ -0,0 +1,239 @@
|
||||||
|
const { isNone, run, makeArray } = Ember;
|
||||||
|
import computed from "ember-addons/ember-computed-decorators";
|
||||||
|
import UtilsMixin from "select-kit/mixins/utils";
|
||||||
|
import DomHelpersMixin from "select-kit/mixins/dom-helpers";
|
||||||
|
import EventsMixin from "select-kit/mixins/events";
|
||||||
|
import PluginApiMixin from "select-kit/mixins/plugin-api";
|
||||||
|
import { applyContentPluginApiCallbacks } from "select-kit/mixins/plugin-api";
|
||||||
|
|
||||||
|
export default Ember.Component.extend(UtilsMixin, PluginApiMixin, DomHelpersMixin, EventsMixin, {
|
||||||
|
pluginApiIdentifiers: ["select-kit"],
|
||||||
|
layoutName: "select-kit/templates/components/select-kit",
|
||||||
|
classNames: ["select-kit", "select-box-kit"],
|
||||||
|
classNameBindings: [
|
||||||
|
"isFocused",
|
||||||
|
"isExpanded",
|
||||||
|
"isDisabled",
|
||||||
|
"isHidden",
|
||||||
|
"isAbove",
|
||||||
|
"isBelow",
|
||||||
|
"isLeftAligned",
|
||||||
|
"isRightAligned"
|
||||||
|
],
|
||||||
|
isDisabled: false,
|
||||||
|
isExpanded: false,
|
||||||
|
isFocused: false,
|
||||||
|
isHidden: false,
|
||||||
|
renderedBodyOnce: false,
|
||||||
|
renderedFilterOnce: false,
|
||||||
|
tabindex: 0,
|
||||||
|
scrollableParentSelector: ".modal-body",
|
||||||
|
none: null,
|
||||||
|
highlightedValue: null,
|
||||||
|
noContentLabel: "select_kit.no_content",
|
||||||
|
valueAttribute: "id",
|
||||||
|
nameProperty: "name",
|
||||||
|
autoFilterable: false,
|
||||||
|
filterable: false,
|
||||||
|
filter: "",
|
||||||
|
filterPlaceholder: "select_kit.filter_placeholder",
|
||||||
|
filterIcon: "search",
|
||||||
|
headerIcon: null,
|
||||||
|
rowComponent: "select-kit/select-kit-row",
|
||||||
|
rowComponentOptions: null,
|
||||||
|
noneRowComponent: "select-kit/select-kit-none-row",
|
||||||
|
createRowComponent: "select-kit/select-kit-create-row",
|
||||||
|
filterComponent: "select-kit/select-kit-filter",
|
||||||
|
headerComponent: "select-kit/select-kit-header",
|
||||||
|
headerComponentOptions: null,
|
||||||
|
headerComputedContent: null,
|
||||||
|
collectionComponent: "select-kit/select-kit-collection",
|
||||||
|
collectionHeight: 200,
|
||||||
|
verticalOffset: 0,
|
||||||
|
horizontalOffset: 0,
|
||||||
|
fullWidthOnMobile: false,
|
||||||
|
castInteger: false,
|
||||||
|
allowAny: false,
|
||||||
|
allowInitialValueMutation: false,
|
||||||
|
content: null,
|
||||||
|
computedContent: null,
|
||||||
|
limitMatches: 100,
|
||||||
|
|
||||||
|
init() {
|
||||||
|
this._super();
|
||||||
|
|
||||||
|
this.noneValue = "__none__";
|
||||||
|
this._previousScrollParentOverflow = "auto";
|
||||||
|
this._previousCSSContext = {};
|
||||||
|
this.set("headerComponentOptions", Ember.Object.create());
|
||||||
|
this.set("rowComponentOptions", Ember.Object.create());
|
||||||
|
this.set("computedContent", []);
|
||||||
|
|
||||||
|
if ($(window).outerWidth(false) <= 420) {
|
||||||
|
this.setProperties({ filterable: false, autoFilterable: false });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
willComputeAttributes() {},
|
||||||
|
didComputeAttributes() {},
|
||||||
|
|
||||||
|
_beforeWillComputeContent(content) { return makeArray(content); },
|
||||||
|
willComputeContent(content) { return content; },
|
||||||
|
computeContent(content) { return content; },
|
||||||
|
_beforeDidComputeContent(content) {
|
||||||
|
content = applyContentPluginApiCallbacks(this.get("pluginApiIdentifiers"), content);
|
||||||
|
|
||||||
|
const existingCreatedComputedContent = this.get("computedContent").filterBy("created", true);
|
||||||
|
this.setProperties({
|
||||||
|
computedContent: content.map(c => this.computeContentItem(c)).concat(existingCreatedComputedContent)
|
||||||
|
});
|
||||||
|
return content;
|
||||||
|
},
|
||||||
|
didComputeContent() {},
|
||||||
|
|
||||||
|
mutateAttributes() {
|
||||||
|
run.next(() => {
|
||||||
|
this.mutateContent(this.get("computedContent"));
|
||||||
|
this.mutateValue(this.get("computedValue"));
|
||||||
|
this.set("headerComputedContent", this.computeHeaderContent());
|
||||||
|
});
|
||||||
|
},
|
||||||
|
mutateContent() {},
|
||||||
|
mutateValue(computedValue) { this.set("value", computedValue); },
|
||||||
|
|
||||||
|
computeHeaderContent() {
|
||||||
|
return this.baseHeaderComputedContent();
|
||||||
|
},
|
||||||
|
|
||||||
|
computeContentItem(contentItem, options) {
|
||||||
|
return this.baseComputedContentItem(contentItem, options);
|
||||||
|
},
|
||||||
|
|
||||||
|
baseComputedContentItem(contentItem, options) {
|
||||||
|
let originalContent;
|
||||||
|
options = options || {};
|
||||||
|
const name = options.name;
|
||||||
|
|
||||||
|
if (typeof contentItem === "string" || typeof contentItem === "number") {
|
||||||
|
originalContent = {};
|
||||||
|
originalContent[this.get("valueAttribute")] = contentItem;
|
||||||
|
originalContent[this.get("nameProperty")] = name || contentItem;
|
||||||
|
} else {
|
||||||
|
originalContent = contentItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
value: this._castInteger(this.valueForContentItem(contentItem)),
|
||||||
|
name: name || this._nameForContent(contentItem),
|
||||||
|
locked: false,
|
||||||
|
created: options.created || false,
|
||||||
|
originalContent
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
@computed("shouldFilter", "allowAny", "filter")
|
||||||
|
shouldDisplayFilter(shouldFilter, allowAny, filter) {
|
||||||
|
if (shouldFilter === true) return true;
|
||||||
|
if (allowAny === true && filter.length > 0) return true;
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
|
@computed("filter", "filteredComputedContent.[]")
|
||||||
|
shouldDisplayNoContentRow(filter, filteredComputedContent) {
|
||||||
|
return filter.length > 0 && filteredComputedContent.length === 0;
|
||||||
|
},
|
||||||
|
|
||||||
|
@computed("filter", "filterable", "autoFilterable", "renderedFilterOnce")
|
||||||
|
shouldFilter(filter, filterable, autoFilterable, renderedFilterOnce) {
|
||||||
|
if (renderedFilterOnce === true && filterable === true) return true;
|
||||||
|
if (filterable === true) return true;
|
||||||
|
if (autoFilterable === true && filter.length > 0) return true;
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
|
@computed("filter", "computedContent")
|
||||||
|
shouldDisplayCreateRow(filter, computedContent) {
|
||||||
|
if (computedContent.map(c => c.value).includes(filter)) return false;
|
||||||
|
if (this.get("allowAny") === true && filter.length > 0) return true;
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
|
@computed("filter", "shouldDisplayCreateRow")
|
||||||
|
createRowComputedContent(filter, shouldDisplayCreateRow) {
|
||||||
|
if (shouldDisplayCreateRow === true) {
|
||||||
|
let content = this.createContentFromInput(filter);
|
||||||
|
return this.computeContentItem(content, { created: true });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
@computed
|
||||||
|
templateForRow() { return () => null; },
|
||||||
|
|
||||||
|
@computed
|
||||||
|
templateForNoneRow() { return () => null; },
|
||||||
|
|
||||||
|
@computed("filter")
|
||||||
|
templateForCreateRow() {
|
||||||
|
return (rowComponent) => {
|
||||||
|
return I18n.t("select_box.create", {
|
||||||
|
content: rowComponent.get("computedContent.name")
|
||||||
|
});
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
@computed("none")
|
||||||
|
noneRowComputedContent(none) {
|
||||||
|
if (isNone(none)) { return null; }
|
||||||
|
|
||||||
|
switch (typeof none) {
|
||||||
|
case "string":
|
||||||
|
return this.computeContentItem(this.noneValue, { name: I18n.t(none) });
|
||||||
|
default:
|
||||||
|
return this.computeContentItem(none);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
createContentFromInput(input) { return input; },
|
||||||
|
|
||||||
|
willSelect() {
|
||||||
|
this.clearFilter();
|
||||||
|
this.set("highlightedValue", null);
|
||||||
|
},
|
||||||
|
didSelect() {
|
||||||
|
this.collapse();
|
||||||
|
this.focus();
|
||||||
|
},
|
||||||
|
|
||||||
|
willDeselect() {
|
||||||
|
this.clearFilter();
|
||||||
|
this.set("highlightedValue", null);
|
||||||
|
},
|
||||||
|
didDeselect() {
|
||||||
|
this.collapse();
|
||||||
|
this.focus();
|
||||||
|
},
|
||||||
|
|
||||||
|
clearFilter() {
|
||||||
|
this.$filterInput().val("");
|
||||||
|
this.setProperties({ filter: "" });
|
||||||
|
},
|
||||||
|
|
||||||
|
actions: {
|
||||||
|
onToggle() {
|
||||||
|
this.get("isExpanded") === true ? this.collapse() : this.expand();
|
||||||
|
},
|
||||||
|
|
||||||
|
onHighlight(rowComputedContent) {
|
||||||
|
this.set("highlightedValue", rowComputedContent.value);
|
||||||
|
},
|
||||||
|
|
||||||
|
onFilter(filter) {
|
||||||
|
this.setProperties({
|
||||||
|
highlightedValue: null,
|
||||||
|
renderedFilterOnce: true,
|
||||||
|
filter
|
||||||
|
});
|
||||||
|
this.autoHighlight();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,5 @@
|
||||||
|
export default Ember.Component.extend({
|
||||||
|
layoutName: "select-kit/templates/components/select-kit/select-kit-collection",
|
||||||
|
classNames: ["select-kit-collection", "select-box-kit-collection"],
|
||||||
|
tagName: "ul"
|
||||||
|
});
|
|
@ -0,0 +1,10 @@
|
||||||
|
import SelectKitRowComponent from "select-kit/components/select-kit/select-kit-row";
|
||||||
|
|
||||||
|
export default SelectKitRowComponent.extend({
|
||||||
|
layoutName: "select-kit/templates/components/select-kit/select-kit-row",
|
||||||
|
classNames: "create",
|
||||||
|
|
||||||
|
click() {
|
||||||
|
this.sendAction("onCreate", this.get("computedContent"));
|
||||||
|
},
|
||||||
|
});
|
|
@ -1,6 +1,6 @@
|
||||||
export default Ember.Component.extend({
|
export default Ember.Component.extend({
|
||||||
layoutName: "select-box-kit/templates/components/select-box-kit/select-box-kit-filter",
|
layoutName: "select-kit/templates/components/select-kit/select-kit-filter",
|
||||||
classNames: "select-box-kit-filter",
|
classNames: ["select-kit-filter", "select-box-kit-filter"],
|
||||||
classNameBindings: ["isFocused", "isHidden"],
|
classNameBindings: ["isFocused", "isHidden"],
|
||||||
isHidden: Ember.computed.not("shouldDisplayFilter")
|
isHidden: Ember.computed.not("shouldDisplayFilter")
|
||||||
});
|
});
|
|
@ -0,0 +1,35 @@
|
||||||
|
import computed from 'ember-addons/ember-computed-decorators';
|
||||||
|
|
||||||
|
export default Ember.Component.extend({
|
||||||
|
layoutName: "select-kit/templates/components/select-kit/select-kit-header",
|
||||||
|
classNames: ["select-kit-header", "select-box-kit-header"],
|
||||||
|
classNameBindings: ["isFocused"],
|
||||||
|
attributeBindings: [
|
||||||
|
"dataName:data-name",
|
||||||
|
"tabindex",
|
||||||
|
"ariaLabel:aria-label",
|
||||||
|
"ariaHasPopup:aria-haspopup",
|
||||||
|
"title"
|
||||||
|
],
|
||||||
|
|
||||||
|
ariaHasPopup: true,
|
||||||
|
|
||||||
|
ariaLabel: Ember.computed.alias("title"),
|
||||||
|
|
||||||
|
name: Ember.computed.alias("computedContent.name"),
|
||||||
|
|
||||||
|
@computed("computedContent.icon", "computedContent.icons")
|
||||||
|
icons(icon, icons) {
|
||||||
|
return Ember.makeArray(icon).concat(icons).filter(i => !Ember.isEmpty(i));
|
||||||
|
},
|
||||||
|
|
||||||
|
@computed("computedContent.dataName", "name")
|
||||||
|
dataName(dataName, name) { return dataName || name; },
|
||||||
|
|
||||||
|
@computed("computedContent.title", "name")
|
||||||
|
title(title, name) { return title || name; },
|
||||||
|
|
||||||
|
click() {
|
||||||
|
this.sendAction("onToggle");
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,10 @@
|
||||||
|
import SelectKitRowComponent from "select-kit/components/select-kit/select-kit-row";
|
||||||
|
|
||||||
|
export default SelectKitRowComponent.extend({
|
||||||
|
layoutName: "select-kit/templates/components/select-kit/select-kit-row",
|
||||||
|
classNames: "none",
|
||||||
|
|
||||||
|
click() {
|
||||||
|
this.sendAction("onClear");
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,58 @@
|
||||||
|
import { on } from 'ember-addons/ember-computed-decorators';
|
||||||
|
import computed from 'ember-addons/ember-computed-decorators';
|
||||||
|
const { run, isPresent, makeArray, isEmpty } = Ember;
|
||||||
|
import UtilsMixin from "select-kit/mixins/utils";
|
||||||
|
|
||||||
|
export default Ember.Component.extend(UtilsMixin, {
|
||||||
|
layoutName: "select-kit/templates/components/select-kit/select-kit-row",
|
||||||
|
classNames: ["select-kit-row", "select-box-kit-row"],
|
||||||
|
tagName: "li",
|
||||||
|
tabIndex: -1,
|
||||||
|
attributeBindings: [
|
||||||
|
"tabIndex",
|
||||||
|
"title",
|
||||||
|
"computedContent.value:data-value",
|
||||||
|
"computedContent.name:data-name"
|
||||||
|
],
|
||||||
|
classNameBindings: ["isHighlighted", "isSelected"],
|
||||||
|
|
||||||
|
@computed("computedContent.title", "computedContent.name")
|
||||||
|
title(title, name) { return title || name; },
|
||||||
|
|
||||||
|
@computed("templateForRow")
|
||||||
|
template(templateForRow) { return templateForRow(this); },
|
||||||
|
|
||||||
|
@on("didReceiveAttrs")
|
||||||
|
_setSelectionState() {
|
||||||
|
const contentValue = this.get("computedContent.value");
|
||||||
|
|
||||||
|
this.set("isSelected", this.get("computedValue") === contentValue);
|
||||||
|
this.set("isHighlighted", this.get("highlightedValue") === contentValue);
|
||||||
|
},
|
||||||
|
|
||||||
|
@on("willDestroyElement")
|
||||||
|
_clearDebounce() {
|
||||||
|
const hoverDebounce = this.get("hoverDebounce");
|
||||||
|
if (isPresent(hoverDebounce)) { run.cancel(hoverDebounce); }
|
||||||
|
},
|
||||||
|
|
||||||
|
@computed("computedContent.icon", "computedContent.icons", "computedContent.originalContent.icon")
|
||||||
|
icons(icon, icons, originalIcon) {
|
||||||
|
return makeArray(icon)
|
||||||
|
.concat(icons)
|
||||||
|
.concat(makeArray(originalIcon))
|
||||||
|
.filter(i => !isEmpty(i));
|
||||||
|
},
|
||||||
|
|
||||||
|
mouseEnter() {
|
||||||
|
this.set("hoverDebounce", run.debounce(this, this._sendOnHighlightAction, 32));
|
||||||
|
},
|
||||||
|
|
||||||
|
click() {
|
||||||
|
this.sendAction("onSelect", this.get("computedContent"));
|
||||||
|
},
|
||||||
|
|
||||||
|
_sendOnHighlightAction() {
|
||||||
|
this.sendAction("onHighlight", this.get("computedContent"));
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,168 @@
|
||||||
|
import SelectKitComponent from "select-kit/components/select-kit";
|
||||||
|
import { on } from "ember-addons/ember-computed-decorators";
|
||||||
|
import computed from "ember-addons/ember-computed-decorators";
|
||||||
|
const { get, isNone, isEmpty, isPresent } = Ember;
|
||||||
|
|
||||||
|
export default SelectKitComponent.extend({
|
||||||
|
pluginApiIdentifiers: ["single-select"],
|
||||||
|
classNames: "single-select",
|
||||||
|
computedValue: null,
|
||||||
|
value: null,
|
||||||
|
allowInitialValueMutation: true,
|
||||||
|
|
||||||
|
init() {
|
||||||
|
this._super();
|
||||||
|
|
||||||
|
if (this.get("allowInitialValueMutation") === true) {
|
||||||
|
const none = isNone(this.get("none"));
|
||||||
|
const emptyValue = isEmpty(this.get("value"));
|
||||||
|
if (none && emptyValue) {
|
||||||
|
if (!isEmpty(this.get("content"))) {
|
||||||
|
const value = this.valueForContentItem(this.get("content.firstObject"));
|
||||||
|
Ember.run.next(() => this.mutateValue(value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
@on("didReceiveAttrs")
|
||||||
|
_compute() {
|
||||||
|
Ember.run.scheduleOnce("afterRender", () => {
|
||||||
|
this.willComputeAttributes();
|
||||||
|
let content = this._beforeWillComputeContent(this.get("content"));
|
||||||
|
content = this.willComputeContent(content);
|
||||||
|
let value = this._beforeWillComputeValue(this.get("value"));
|
||||||
|
content = this.computeContent(content);
|
||||||
|
content = this._beforeDidComputeContent(content);
|
||||||
|
value = this.willComputeValue(value);
|
||||||
|
value = this.computeValue(value);
|
||||||
|
value = this._beforeDidComputeValue(value);
|
||||||
|
this.didComputeContent(content);
|
||||||
|
this.didComputeValue(value);
|
||||||
|
this.set("headerComputedContent", this.computeHeaderContent());
|
||||||
|
this.didComputeAttributes();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
_beforeWillComputeValue(value) {
|
||||||
|
switch (typeof value) {
|
||||||
|
case "string":
|
||||||
|
case "number":
|
||||||
|
return this._castInteger(value === "" ? null : value);
|
||||||
|
default:
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
willComputeValue(value) { return value; },
|
||||||
|
computeValue(value) { return value; },
|
||||||
|
_beforeDidComputeValue(value) {
|
||||||
|
if (!isEmpty(this.get("content")) && isNone(value) && isNone(this.get("none"))) {
|
||||||
|
value = this.valueForContentItem(get(this.get("content"), "firstObject"));
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setProperties({ computedValue: value });
|
||||||
|
return value;
|
||||||
|
},
|
||||||
|
didComputeValue(value) { return value; },
|
||||||
|
|
||||||
|
filterComputedContent(computedContent, computedValue, filter) {
|
||||||
|
const lowerFilter = filter.toLowerCase();
|
||||||
|
return computedContent.filter(c => {
|
||||||
|
return get(c, "name").toLowerCase().indexOf(lowerFilter) > -1;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
baseHeaderComputedContent() {
|
||||||
|
return {
|
||||||
|
icons: Ember.makeArray(this.getWithDefault("headerIcon", [])),
|
||||||
|
name: this.get("selectedComputedContent.name") || this.get("noneRowComputedContent.name")
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
@computed("computedContent.[]", "computedValue", "filter", "shouldFilter")
|
||||||
|
filteredComputedContent(computedContent, computedValue, filter, shouldFilter) {
|
||||||
|
if (shouldFilter === true) {
|
||||||
|
computedContent = this.filterComputedContent(computedContent, computedValue, filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
return computedContent.slice(0, this.get("limitMatches"));
|
||||||
|
},
|
||||||
|
|
||||||
|
@computed("computedValue", "computedContent.[]")
|
||||||
|
selectedComputedContent(computedValue, computedContent) {
|
||||||
|
if (isNone(computedValue) || isNone(computedContent)) { return null; }
|
||||||
|
return computedContent.findBy("value", computedValue);
|
||||||
|
},
|
||||||
|
|
||||||
|
@computed("selectedComputedContent")
|
||||||
|
hasSelection(selectedComputedContent) {
|
||||||
|
return selectedComputedContent !== this.get("noneRowComputedContent") &&
|
||||||
|
!Ember.isNone(selectedComputedContent);
|
||||||
|
},
|
||||||
|
|
||||||
|
@computed("filter", "computedValue")
|
||||||
|
shouldDisplayCreateRow(filter, computedValue) {
|
||||||
|
return this._super() && computedValue !== filter;
|
||||||
|
},
|
||||||
|
|
||||||
|
autoHighlight() {
|
||||||
|
Ember.run.schedule("afterRender", () => {
|
||||||
|
if (!isNone(this.get("highlightedValue"))) { return; }
|
||||||
|
|
||||||
|
const filteredComputedContent = this.get("filteredComputedContent");
|
||||||
|
const displayCreateRow = this.get("shouldDisplayCreateRow");
|
||||||
|
const none = this.get("noneRowComputedContent");
|
||||||
|
|
||||||
|
if (this.get("hasSelection") && isEmpty(this.get("filter"))) {
|
||||||
|
this.send("onHighlight", this.get("selectedComputedContent"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isNone(this.get("highlightedValue")) && !isEmpty(filteredComputedContent)) {
|
||||||
|
this.send("onHighlight", get(filteredComputedContent, "firstObject"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (displayCreateRow === true && isEmpty(filteredComputedContent)) {
|
||||||
|
this.send("onHighlight", this.get("createRowComputedContent"));
|
||||||
|
}
|
||||||
|
else if (!isEmpty(filteredComputedContent)) {
|
||||||
|
this.send("onHighlight", get(filteredComputedContent, "firstObject"));
|
||||||
|
}
|
||||||
|
else if (isEmpty(filteredComputedContent) && isPresent(none) && displayCreateRow === false) {
|
||||||
|
this.send("onHighlight", none);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
validateComputedContentItem(computedContentItem) {
|
||||||
|
return this.get("computedValue") !== computedContentItem.value;
|
||||||
|
},
|
||||||
|
|
||||||
|
actions: {
|
||||||
|
onClear() {
|
||||||
|
this.send("onDeselect", this.get("selectedComputedContent"));
|
||||||
|
},
|
||||||
|
|
||||||
|
onCreate(computedContentItem) {
|
||||||
|
if (this.validateComputedContentItem(computedContentItem)) {
|
||||||
|
this.get("computedContent").pushObject(computedContentItem);
|
||||||
|
this.send("onSelect", computedContentItem);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
onSelect(rowComputedContentItem) {
|
||||||
|
this.willSelect(rowComputedContentItem);
|
||||||
|
this.set("computedValue", rowComputedContentItem.value);
|
||||||
|
this.mutateAttributes();
|
||||||
|
Ember.run.schedule("afterRender", () => this.didSelect(rowComputedContentItem));
|
||||||
|
},
|
||||||
|
|
||||||
|
onDeselect(rowComputedContentItem) {
|
||||||
|
this.willDeselect(rowComputedContentItem);
|
||||||
|
this.set("computedValue", null);
|
||||||
|
this.mutateAttributes();
|
||||||
|
Ember.run.schedule("afterRender", () => this.didDeselect(rowComputedContentItem));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,23 @@
|
||||||
|
import NotificationOptionsComponent from "select-kit/components/notifications-button";
|
||||||
|
import computed from "ember-addons/ember-computed-decorators";
|
||||||
|
|
||||||
|
export default NotificationOptionsComponent.extend({
|
||||||
|
pluginApiIdentifiers: ["tag-notifications-button"],
|
||||||
|
classNames: "tag-notifications-button",
|
||||||
|
i18nPrefix: "tagging.notifications",
|
||||||
|
showFullTitle: false,
|
||||||
|
allowInitialValueMutation: false,
|
||||||
|
|
||||||
|
mutateValue(value) {
|
||||||
|
this.sendAction("action", value);
|
||||||
|
},
|
||||||
|
|
||||||
|
computeValue() {
|
||||||
|
return this.get("notificationLevel");
|
||||||
|
},
|
||||||
|
|
||||||
|
@computed("iconForSelectedDetails")
|
||||||
|
headerIcon(iconForSelectedDetails) {
|
||||||
|
return [iconForSelectedDetails, "caret-down"];
|
||||||
|
}
|
||||||
|
});
|
|
@ -1,24 +1,21 @@
|
||||||
import computed from "ember-addons/ember-computed-decorators";
|
import ComboBoxComponent from "select-kit/components/combo-box";
|
||||||
import ComboBoxComponent from "select-box-kit/components/combo-box";
|
|
||||||
import { on } from "ember-addons/ember-computed-decorators";
|
|
||||||
|
|
||||||
export default ComboBoxComponent.extend({
|
export default ComboBoxComponent.extend({
|
||||||
headerText: "topic.controls",
|
pluginApiIdentifiers: ["topic-footer-mobile-dropdown"],
|
||||||
classNames: "topic-footer-mobile-dropdown",
|
classNames: "topic-footer-mobile-dropdown",
|
||||||
filterable: false,
|
filterable: false,
|
||||||
autoFilterable: false,
|
autoFilterable: false,
|
||||||
allowValueMutation: false,
|
allowInitialValueMutation: false,
|
||||||
autoSelectFirst: false,
|
|
||||||
|
|
||||||
@on("didReceiveAttrs")
|
computeHeaderContent() {
|
||||||
_setTopicFooterMobileDropdownOptions() {
|
let content = this.baseHeaderComputedContent();
|
||||||
this.get("headerComponentOptions")
|
content.name = I18n.t("topic.controls");
|
||||||
.set("selectedName", I18n.t(this.get("headerText")));
|
return content;
|
||||||
},
|
},
|
||||||
|
|
||||||
@computed("topic", "topic.details", "value")
|
computeContent(content) {
|
||||||
content(topic, details) {
|
const topic = this.get("topic");
|
||||||
const content = [];
|
const details = topic.get("details");
|
||||||
|
|
||||||
if (details.get("can_invite_to")) {
|
if (details.get("can_invite_to")) {
|
||||||
content.push({ id: "invite", icon: "users", name: I18n.t("topic.invite_reply.title") });
|
content.push({ id: "invite", icon: "users", name: I18n.t("topic.invite_reply.title") });
|
||||||
|
@ -39,16 +36,15 @@ export default ComboBoxComponent.extend({
|
||||||
return content;
|
return content;
|
||||||
},
|
},
|
||||||
|
|
||||||
selectValueFunction(value) {
|
autoHighlight() {},
|
||||||
|
|
||||||
|
mutateValue(value) {
|
||||||
const topic = this.get("topic");
|
const topic = this.get("topic");
|
||||||
|
|
||||||
// In case it"s not a valid topic
|
|
||||||
if (!topic.get("id")) {
|
if (!topic.get("id")) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.set("value", value);
|
|
||||||
|
|
||||||
const refresh = () => this.send("onDeselect", value);
|
const refresh = () => this.send("onDeselect", value);
|
||||||
|
|
||||||
switch(value) {
|
switch(value) {
|
|
@ -1,5 +1,5 @@
|
||||||
export default Ember.Component.extend({
|
export default Ember.Component.extend({
|
||||||
layoutName: "select-box-kit/templates/components/topic-notifications-button",
|
layoutName: "select-kit/templates/components/topic-notifications-button",
|
||||||
classNames: "topic-notifications-button",
|
classNames: "topic-notifications-button",
|
||||||
showFullTitle: true,
|
showFullTitle: true,
|
||||||
appendReason: true
|
appendReason: true
|
|
@ -1,12 +1,13 @@
|
||||||
import NotificationOptionsComponent from "select-box-kit/components/notifications-button";
|
import NotificationOptionsComponent from "select-kit/components/notifications-button";
|
||||||
import { on } from "ember-addons/ember-computed-decorators";
|
import { on } from "ember-addons/ember-computed-decorators";
|
||||||
import { topicLevels } from "discourse/lib/notification-levels";
|
import { topicLevels } from "discourse/lib/notification-levels";
|
||||||
|
|
||||||
export default NotificationOptionsComponent.extend({
|
export default NotificationOptionsComponent.extend({
|
||||||
|
pluginApiIdentifiers: ["topic-notifications-options"],
|
||||||
classNames: "topic-notifications-options",
|
classNames: "topic-notifications-options",
|
||||||
content: topicLevels,
|
content: topicLevels,
|
||||||
i18nPrefix: "topic.notifications",
|
i18nPrefix: "topic.notifications",
|
||||||
value: Ember.computed.alias("topic.details.notification_level"),
|
allowInitialValueMutation: false,
|
||||||
|
|
||||||
@on("didInsertElement")
|
@on("didInsertElement")
|
||||||
_bindGlobalLevelChanged() {
|
_bindGlobalLevelChanged() {
|
||||||
|
@ -24,11 +25,9 @@ export default NotificationOptionsComponent.extend({
|
||||||
this.appEvents.off("topic-notifications-button:changed");
|
this.appEvents.off("topic-notifications-button:changed");
|
||||||
},
|
},
|
||||||
|
|
||||||
selectValueFunction(value) {
|
mutateValue(value) {
|
||||||
if (value !== this.get("value")) {
|
if (value !== this.get("value")) {
|
||||||
this.get("topic.details").updateNotifications(value);
|
this.get("topic.details").updateNotifications(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.set("value", value);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
|
@ -4,13 +4,12 @@ export default Ember.Mixin.create({
|
||||||
init() {
|
init() {
|
||||||
this._super();
|
this._super();
|
||||||
|
|
||||||
this.offscreenInputSelector = ".select-box-kit-offscreen";
|
this.filterInputSelector = ".filter-input";
|
||||||
this.filterInputSelector = ".select-box-kit-filter-input";
|
this.rowSelector = ".select-kit-row";
|
||||||
this.rowSelector = ".select-box-kit-row";
|
this.collectionSelector = ".select-kit-collection";
|
||||||
this.collectionSelector = ".select-box-kit-collection";
|
this.headerSelector = ".select-kit-header";
|
||||||
this.headerSelector = ".select-box-kit-header";
|
this.bodySelector = ".select-kit-body";
|
||||||
this.bodySelector = ".select-box-kit-body";
|
this.wrapperSelector = ".select-kit-wrapper";
|
||||||
this.wrapperSelector = ".select-box-kit-wrapper";
|
|
||||||
},
|
},
|
||||||
|
|
||||||
$findRowByValue(value) { return this.$(`${this.rowSelector}[data-value='${value}']`); },
|
$findRowByValue(value) { return this.$(`${this.rowSelector}[data-value='${value}']`); },
|
||||||
|
@ -34,45 +33,50 @@ export default Ember.Mixin.create({
|
||||||
|
|
||||||
$selectedRow() { return this.$rows().filter(".is-selected"); },
|
$selectedRow() { return this.$rows().filter(".is-selected"); },
|
||||||
|
|
||||||
$offscreenInput() { return this.$(this.offscreenInputSelector); },
|
|
||||||
|
|
||||||
$filterInput() { return this.$(this.filterInputSelector); },
|
$filterInput() { return this.$(this.filterInputSelector); },
|
||||||
|
|
||||||
@on("didRender")
|
@on("didRender")
|
||||||
_ajustPosition() {
|
_ajustPosition() {
|
||||||
$(`.select-box-kit-fixed-placeholder-${this.elementId}`).remove();
|
$(`.select-kit-fixed-placeholder-${this.elementId}`).remove();
|
||||||
this.$collection().css("max-height", this.get("collectionHeight"));
|
this.$collection().css("max-height", this.get("collectionHeight"));
|
||||||
this._applyFixedPosition();
|
this._applyFixedPosition();
|
||||||
this._applyDirection();
|
this._applyDirection();
|
||||||
this._positionWrapper();
|
this._positionWrapper();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@on("didInsertElement")
|
||||||
|
_setupResizeListener() {
|
||||||
|
$(window).on("resize.select-kit", () => this.collapse() );
|
||||||
|
},
|
||||||
|
|
||||||
@on("willDestroyElement")
|
@on("willDestroyElement")
|
||||||
_clearState() {
|
_clearState() {
|
||||||
$(window).off("resize.select-box-kit");
|
$(window).off("resize.select-kit");
|
||||||
$(`.select-box-kit-fixed-placeholder-${this.elementId}`).remove();
|
$(`.select-kit-fixed-placeholder-${this.elementId}`).remove();
|
||||||
},
|
},
|
||||||
|
|
||||||
// make sure we don’t propagate a click outside component
|
// make sure we don’t propagate a click outside component
|
||||||
// to avoid closing a modal containing the component for example
|
// to avoid closing a modal containing the component for example
|
||||||
click(event) { this._killEvent(event); },
|
click(event) {
|
||||||
|
this._destroyEvent(event);
|
||||||
|
},
|
||||||
|
|
||||||
// use to collapse and remove focus
|
// use to collapse and remove focus
|
||||||
close() {
|
close(event) {
|
||||||
this.collapse();
|
this.collapse(event);
|
||||||
this.setProperties({ isFocused: false });
|
this.setProperties({ isFocused: false });
|
||||||
},
|
},
|
||||||
|
|
||||||
// force the component in a known default state
|
// force the component in a known default state
|
||||||
focus() {
|
focus() {
|
||||||
Ember.run.schedule("afterRender", () => this.$offscreenInput().select() );
|
Ember.run.schedule("afterRender", () => this.$header().focus() );
|
||||||
},
|
},
|
||||||
|
|
||||||
expand() {
|
expand(event) {
|
||||||
if (this.get("isExpanded") === true) { return; }
|
if (this.get("isExpanded") === true) return;
|
||||||
this.setProperties({ isExpanded: true, renderedBodyOnce: true, isFocused: true });
|
this.setProperties({ isExpanded: true, renderedBodyOnce: true, isFocused: true });
|
||||||
this.focus();
|
this.focus(event);
|
||||||
this.autoHighlightFunction();
|
this.autoHighlight();
|
||||||
},
|
},
|
||||||
|
|
||||||
collapse() {
|
collapse() {
|
||||||
|
@ -80,35 +84,18 @@ export default Ember.Mixin.create({
|
||||||
Ember.run.schedule("afterRender", () => this._removeFixedPosition() );
|
Ember.run.schedule("afterRender", () => this._removeFixedPosition() );
|
||||||
},
|
},
|
||||||
|
|
||||||
// make sure we close/unfocus the component when clicked outside
|
|
||||||
clickOutside(event) {
|
|
||||||
if ($(event.target).parents(".select-box-kit").length === 1) {
|
|
||||||
this.close();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.unfocus();
|
|
||||||
return;
|
|
||||||
},
|
|
||||||
|
|
||||||
// lose focus of the component in two steps
|
// lose focus of the component in two steps
|
||||||
// first collapase and keep focus and then remove focus
|
// first collapse and keep focus and then remove focus
|
||||||
unfocus() {
|
unfocus(event) {
|
||||||
this.set("highlightedValue", null);
|
|
||||||
|
|
||||||
if (this.get("isExpanded") === true) {
|
if (this.get("isExpanded") === true) {
|
||||||
this.collapse();
|
this.collapse(event);
|
||||||
this.focus();
|
this.focus(event);
|
||||||
} else {
|
} else {
|
||||||
this.close();
|
this.close(event);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
blur() {
|
_destroyEvent(event) {
|
||||||
Ember.run.schedule("afterRender", () => this.$offscreenInput().blur() );
|
|
||||||
},
|
|
||||||
|
|
||||||
_killEvent(event) {
|
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
},
|
},
|
||||||
|
@ -119,8 +106,8 @@ export default Ember.Mixin.create({
|
||||||
const dHeader = $(".d-header")[0];
|
const dHeader = $(".d-header")[0];
|
||||||
const dHeaderBounds = dHeader ? dHeader.getBoundingClientRect() : {top: 0, height: 0};
|
const dHeaderBounds = dHeader ? dHeader.getBoundingClientRect() : {top: 0, height: 0};
|
||||||
const dHeaderHeight = dHeaderBounds.top + dHeaderBounds.height;
|
const dHeaderHeight = dHeaderBounds.top + dHeaderBounds.height;
|
||||||
const headerHeight = this.$header().outerHeight(false);
|
const componentHeight = this.$().outerHeight(false);
|
||||||
const headerWidth = this.$header().outerWidth(false);
|
const componentWidth = this.$().outerWidth(false);
|
||||||
const bodyHeight = this.$body().outerHeight(false);
|
const bodyHeight = this.$body().outerHeight(false);
|
||||||
const windowWidth = $(window).width();
|
const windowWidth = $(window).width();
|
||||||
const windowHeight = $(window).height();
|
const windowHeight = $(window).height();
|
||||||
|
@ -145,7 +132,7 @@ export default Ember.Mixin.create({
|
||||||
options.left = bodyWidth + this.get("horizontalOffset");
|
options.left = bodyWidth + this.get("horizontalOffset");
|
||||||
} else {
|
} else {
|
||||||
this.setProperties({ isLeftAligned: false, isRightAligned: true });
|
this.setProperties({ isLeftAligned: false, isRightAligned: true });
|
||||||
options.right = - (bodyWidth - headerWidth + this.get("horizontalOffset"));
|
options.right = - (bodyWidth - componentWidth + this.get("horizontalOffset"));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const horizontalSpacing = boundingRect.left;
|
const horizontalSpacing = boundingRect.left;
|
||||||
|
@ -160,15 +147,15 @@ export default Ember.Mixin.create({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const componentHeight = this.get("verticalOffset") + bodyHeight + headerHeight;
|
const fullHeight = this.get("verticalOffset") + bodyHeight + componentHeight;
|
||||||
const hasBelowSpace = windowHeight - offsetBottom - componentHeight > 0;
|
const hasBelowSpace = windowHeight - offsetBottom - fullHeight > 0;
|
||||||
const hasAboveSpace = offsetTop - componentHeight - dHeaderHeight > 0;
|
const hasAboveSpace = offsetTop - fullHeight - dHeaderHeight > 0;
|
||||||
if (hasBelowSpace || (!hasBelowSpace && !hasAboveSpace)) {
|
if (hasBelowSpace || (!hasBelowSpace && !hasAboveSpace)) {
|
||||||
this.setProperties({ isBelow: true, isAbove: false });
|
this.setProperties({ isBelow: true, isAbove: false });
|
||||||
options.top = headerHeight + this.get("verticalOffset");
|
options.top = componentHeight + this.get("verticalOffset") - 2;
|
||||||
} else {
|
} else {
|
||||||
this.setProperties({ isBelow: false, isAbove: true });
|
this.setProperties({ isBelow: false, isAbove: true });
|
||||||
options.bottom = headerHeight + this.get("verticalOffset");
|
options.bottom = componentHeight + this.get("verticalOffset") - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.$body().css(options);
|
this.$body().css(options);
|
||||||
|
@ -182,7 +169,7 @@ export default Ember.Mixin.create({
|
||||||
|
|
||||||
const width = this.$().outerWidth(false);
|
const width = this.$().outerWidth(false);
|
||||||
const height = this.$().outerHeight(false);
|
const height = this.$().outerHeight(false);
|
||||||
const $placeholder = $(`<div class='select-box-kit-fixed-placeholder-${this.elementId}'></div>`);
|
const $placeholder = $(`<div class='select-kit-fixed-placeholder-${this.elementId}'></div>`);
|
||||||
|
|
||||||
this._previousScrollParentOverflow = this._previousScrollParentOverflow || scrollableParent.css("overflow");
|
this._previousScrollParentOverflow = this._previousScrollParentOverflow || scrollableParent.css("overflow");
|
||||||
scrollableParent.css({ overflow: "hidden" });
|
scrollableParent.css({ overflow: "hidden" });
|
||||||
|
@ -212,7 +199,7 @@ export default Ember.Mixin.create({
|
||||||
},
|
},
|
||||||
|
|
||||||
_removeFixedPosition() {
|
_removeFixedPosition() {
|
||||||
$(`.select-box-kit-fixed-placeholder-${this.elementId}`).remove();
|
$(`.select-kit-fixed-placeholder-${this.elementId}`).remove();
|
||||||
|
|
||||||
if (!this.element || this.isDestroying || this.isDestroyed) { return; }
|
if (!this.element || this.isDestroying || this.isDestroyed) { return; }
|
||||||
|
|
||||||
|
@ -236,11 +223,11 @@ export default Ember.Mixin.create({
|
||||||
},
|
},
|
||||||
|
|
||||||
_positionWrapper() {
|
_positionWrapper() {
|
||||||
const headerHeight = this.$header().outerHeight(false);
|
const componentHeight = this.$().outerHeight(false);
|
||||||
|
|
||||||
this.$(this.wrapperSelector).css({
|
this.$(this.wrapperSelector).css({
|
||||||
width: this.$().outerWidth(false),
|
width: this.$().outerWidth(false) - 2,
|
||||||
height: headerHeight + this.$body().outerHeight(false)
|
height: componentHeight + this.$body().outerHeight(false)
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
|
@ -0,0 +1,233 @@
|
||||||
|
export default Ember.Mixin.create({
|
||||||
|
init() {
|
||||||
|
this._super();
|
||||||
|
|
||||||
|
this.keys = {
|
||||||
|
TAB: 9,
|
||||||
|
ENTER: 13,
|
||||||
|
ESC: 27,
|
||||||
|
UP: 38,
|
||||||
|
DOWN: 40,
|
||||||
|
BACKSPACE: 8,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
willDestroyElement() {
|
||||||
|
this._super();
|
||||||
|
|
||||||
|
$(document)
|
||||||
|
.off("mousedown.select-kit")
|
||||||
|
.off("touchstart.select-kit");
|
||||||
|
|
||||||
|
this.$header()
|
||||||
|
.off("focus.select-kit")
|
||||||
|
.off("blur.select-kit")
|
||||||
|
.off("keypress.select-kit")
|
||||||
|
.off("keydown.select-kit");
|
||||||
|
|
||||||
|
this.$filterInput()
|
||||||
|
.off("change.select-kit")
|
||||||
|
.off("keydown.select-kit")
|
||||||
|
.off("focus.select-kit")
|
||||||
|
.off("focusin.select-kit");
|
||||||
|
},
|
||||||
|
|
||||||
|
didInsertElement() {
|
||||||
|
this._super();
|
||||||
|
|
||||||
|
$(document)
|
||||||
|
.on("mousedown.select-kit, touchstart.select-kit", event => {
|
||||||
|
if (Ember.isNone(this.get("element"))) return;
|
||||||
|
if (this.get("element").contains(event.target)) return;
|
||||||
|
|
||||||
|
this.didClickOutside(event);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.$header()
|
||||||
|
.on("blur.select-kit", () => {
|
||||||
|
if (this.get("isExpanded") === false && this.get("isFocused") === true) {
|
||||||
|
this.close();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.on("focus.select-kit", (event) => {
|
||||||
|
this.set("isFocused", true);
|
||||||
|
this._destroyEvent(event);
|
||||||
|
})
|
||||||
|
.on("keydown.select-kit", (event) => {
|
||||||
|
const keyCode = event.keyCode || event.which;
|
||||||
|
|
||||||
|
if (document.activeElement !== this.$header()[0]) return event;
|
||||||
|
|
||||||
|
if (keyCode === this.keys.TAB) this.tabFromHeader(event);
|
||||||
|
if (keyCode === this.keys.BACKSPACE) this.backspaceFromHeader(event);
|
||||||
|
if (keyCode === this.keys.ESC) this.escapeFromHeader(event);
|
||||||
|
if (keyCode === this.keys.ENTER) this.enterFromHeader(event);
|
||||||
|
if ([this.keys.UP, this.keys.DOWN].includes(keyCode)) this.upAndDownFromHeader(event);
|
||||||
|
return event;
|
||||||
|
})
|
||||||
|
.on("keypress.select-kit", (event) => {
|
||||||
|
const keyCode = event.keyCode || event.which;
|
||||||
|
|
||||||
|
if (keyCode === this.keys.ENTER) { return true; }
|
||||||
|
|
||||||
|
this.expand(event);
|
||||||
|
|
||||||
|
if (this.get("filterable") === true || this.get("autoFilterable")) {
|
||||||
|
this.set("renderedFilterOnce", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ember.run.schedule("afterRender", () => {
|
||||||
|
let newVal = this.$filterInput().val();
|
||||||
|
|
||||||
|
const start = this.$filterInput()[0].selectionStart;
|
||||||
|
const end = this.$filterInput()[0].selectionEnd;
|
||||||
|
if (!Ember.isNone(start) && !Ember.isNone(end)) {
|
||||||
|
newVal = newVal.substr(0, start) +
|
||||||
|
String.fromCharCode(keyCode) +
|
||||||
|
newVal.substr(end, newVal.length);
|
||||||
|
} else {
|
||||||
|
newVal = newVal + String.fromCharCode(keyCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$filterInput().focus().val(newVal);
|
||||||
|
});
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.$filterInput()
|
||||||
|
.on("change.select-kit", (event) => {
|
||||||
|
this.send("onFilter", $(event.target).val());
|
||||||
|
})
|
||||||
|
.on("focus.select-kit focusin.select-kit", (event) => {
|
||||||
|
this.set("isFocused", true);
|
||||||
|
this._destroyEvent(event);
|
||||||
|
})
|
||||||
|
.on("keydown.select-kit", (event) => {
|
||||||
|
const keyCode = event.keyCode || event.which;
|
||||||
|
|
||||||
|
if (keyCode === this.keys.TAB) this.tabFromFilter(event);
|
||||||
|
if (keyCode === this.keys.ESC) this.escapeFromFilter(event);
|
||||||
|
if (keyCode === this.keys.ENTER) this.enterFromFilter(event);
|
||||||
|
if ([this.keys.UP, this.keys.DOWN].includes(keyCode)) this.upAndDownFromFilter(event);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
didPressTab(event) {
|
||||||
|
if (this.get("isExpanded") === false) {
|
||||||
|
this.unfocus(event);
|
||||||
|
} else if (this.$highlightedRow().length === 1) {
|
||||||
|
this._destroyEvent(event);
|
||||||
|
Ember.run.throttle(this, this._rowClick, this.$highlightedRow(), 150, 150, true);
|
||||||
|
this.focus(event);
|
||||||
|
} else {
|
||||||
|
this._destroyEvent(event);
|
||||||
|
this.unfocus(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
|
||||||
|
didPressEscape(event) {
|
||||||
|
this._destroyEvent(event);
|
||||||
|
this.unfocus(event);
|
||||||
|
},
|
||||||
|
|
||||||
|
didPressUpAndDownArrows(event) {
|
||||||
|
this._destroyEvent(event);
|
||||||
|
|
||||||
|
const keyCode = event.keyCode || event.which;
|
||||||
|
const $rows = this.$rows();
|
||||||
|
|
||||||
|
if (this.get("isExpanded") === false) {
|
||||||
|
this.expand(event);
|
||||||
|
|
||||||
|
if (this.$selectedRow().length === 1) {
|
||||||
|
this._highlightRow(this.$selectedRow());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($rows.length <= 0) { return; }
|
||||||
|
if ($rows.length === 1) {
|
||||||
|
this._rowSelection($rows, 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const direction = keyCode === 38 ? -1 : 1;
|
||||||
|
|
||||||
|
Ember.run.throttle(this, this._moveHighlight, direction, $rows, 32);
|
||||||
|
},
|
||||||
|
|
||||||
|
didPressBackspace(event) {
|
||||||
|
this._destroyEvent(event);
|
||||||
|
|
||||||
|
this.expand(event);
|
||||||
|
|
||||||
|
if (this.$filterInput().is(":visible")) {
|
||||||
|
this.$filterInput().focus().trigger(event).trigger("change");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
didPressEnter(event) {
|
||||||
|
this._destroyEvent(event);
|
||||||
|
|
||||||
|
if (this.get("isExpanded") === false) {
|
||||||
|
this.expand(event);
|
||||||
|
} else if (this.$highlightedRow().length === 1) {
|
||||||
|
Ember.run.throttle(this, this._rowClick, this.$highlightedRow(), 150, true);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
didClickOutside(event) {
|
||||||
|
if ($(event.target).parents(".select-kit").length === 1) {
|
||||||
|
this.close(event);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.unfocus(event);
|
||||||
|
return;
|
||||||
|
},
|
||||||
|
|
||||||
|
tabFromHeader(event) { this.didPressTab(event); },
|
||||||
|
tabFromFilter(event) { this.didPressTab(event); },
|
||||||
|
|
||||||
|
escapeFromHeader(event) { this.didPressEscape(event); },
|
||||||
|
escapeFromFilter(event) { this.didPressEscape(event); },
|
||||||
|
|
||||||
|
upAndDownFromHeader(event) { this.didPressUpAndDownArrows(event); },
|
||||||
|
upAndDownFromFilter(event) { this.didPressUpAndDownArrows(event); },
|
||||||
|
|
||||||
|
backspaceFromHeader(event) { this.didPressBackspace(event); },
|
||||||
|
|
||||||
|
enterFromHeader(event) { this.didPressEnter(event); },
|
||||||
|
enterFromFilter(event) { this.didPressEnter(event); },
|
||||||
|
|
||||||
|
_moveHighlight(direction, $rows) {
|
||||||
|
const currentIndex = $rows.index(this.$highlightedRow());
|
||||||
|
let nextIndex = currentIndex + direction;
|
||||||
|
|
||||||
|
if (nextIndex < 0) {
|
||||||
|
nextIndex = $rows.length - 1;
|
||||||
|
} else if (nextIndex >= $rows.length) {
|
||||||
|
nextIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._rowSelection($rows, nextIndex);
|
||||||
|
},
|
||||||
|
|
||||||
|
_rowClick($row) { $row.click(); },
|
||||||
|
|
||||||
|
_rowSelection($rows, nextIndex) {
|
||||||
|
const highlightableValue = $rows.eq(nextIndex).attr("data-value");
|
||||||
|
const $highlightableRow = this.$findRowByValue(highlightableValue);
|
||||||
|
this._highlightRow($highlightableRow);
|
||||||
|
},
|
||||||
|
|
||||||
|
_highlightRow($row) {
|
||||||
|
Ember.run.schedule("afterRender", () => {
|
||||||
|
$row.trigger("mouseover").focus();
|
||||||
|
this.focus();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,71 @@
|
||||||
|
let _appendContentCallbacks = {};
|
||||||
|
function appendContent(pluginApiIdentifiers, contentFunction) {
|
||||||
|
if (Ember.isNone(_appendContentCallbacks[pluginApiIdentifiers])) {
|
||||||
|
_appendContentCallbacks[pluginApiIdentifiers] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
_appendContentCallbacks[pluginApiIdentifiers].push(contentFunction);
|
||||||
|
}
|
||||||
|
|
||||||
|
let _prependContentCallbacks = {};
|
||||||
|
function prependContent(pluginApiIdentifiers, contentFunction) {
|
||||||
|
if (Ember.isNone(_prependContentCallbacks[pluginApiIdentifiers])) {
|
||||||
|
_prependContentCallbacks[pluginApiIdentifiers] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
_prependContentCallbacks[pluginApiIdentifiers].push(contentFunction);
|
||||||
|
}
|
||||||
|
|
||||||
|
let _modifyContentCallbacks = {};
|
||||||
|
function modifyContent(pluginApiIdentifiers, contentFunction) {
|
||||||
|
if (Ember.isNone(_modifyContentCallbacks[pluginApiIdentifiers])) {
|
||||||
|
_modifyContentCallbacks[pluginApiIdentifiers] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
_modifyContentCallbacks[pluginApiIdentifiers].push(contentFunction);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function applyContentPluginApiCallbacks(identifiers, content) {
|
||||||
|
identifiers.forEach((key) => {
|
||||||
|
(_prependContentCallbacks[key] || []).forEach((c) => {
|
||||||
|
content = c().concat(content);
|
||||||
|
});
|
||||||
|
(_appendContentCallbacks[key] || []).forEach((c) => {
|
||||||
|
content = content.concat(c());
|
||||||
|
});
|
||||||
|
(_modifyContentCallbacks[key] || []).forEach((c) => {
|
||||||
|
content = c(content);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function modifySelectKit(pluginApiIdentifiers) {
|
||||||
|
return {
|
||||||
|
appendContent: (content) => {
|
||||||
|
appendContent(pluginApiIdentifiers, () => {return content;} );
|
||||||
|
return modifySelectKit(pluginApiIdentifiers);
|
||||||
|
},
|
||||||
|
prependContent: (content) => {
|
||||||
|
prependContent(pluginApiIdentifiers, () => {return content;} );
|
||||||
|
return modifySelectKit(pluginApiIdentifiers);
|
||||||
|
},
|
||||||
|
modifyContent: (callback) => {
|
||||||
|
modifyContent(pluginApiIdentifiers, callback);
|
||||||
|
return modifySelectKit(pluginApiIdentifiers);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function clearCallbacks() {
|
||||||
|
_appendContentCallbacks = {};
|
||||||
|
_prependContentCallbacks = {};
|
||||||
|
_modifyContentCallbacks = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const EMPTY_ARRAY = Object.freeze([]);
|
||||||
|
export default Ember.Mixin.create({
|
||||||
|
concatenatedProperties: ["pluginApiIdentifiers"],
|
||||||
|
pluginApiIdentifiers: EMPTY_ARRAY
|
||||||
|
});
|
|
@ -1,6 +1,16 @@
|
||||||
const { get, isNone } = Ember;
|
const { get, isNone, guidFor } = Ember;
|
||||||
|
|
||||||
export default Ember.Mixin.create({
|
export default Ember.Mixin.create({
|
||||||
|
valueForContentItem(content) {
|
||||||
|
switch (typeof content) {
|
||||||
|
case "string":
|
||||||
|
case "number":
|
||||||
|
return content;
|
||||||
|
default:
|
||||||
|
return get(content, this.get("valueAttribute"));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
_nameForContent(content) {
|
_nameForContent(content) {
|
||||||
if (isNone(content)) {
|
if (isNone(content)) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -25,37 +35,13 @@ export default Ember.Mixin.create({
|
||||||
return value;
|
return value;
|
||||||
},
|
},
|
||||||
|
|
||||||
_valueForContent(content) {
|
_findComputedContentItemByGuid(guid) {
|
||||||
switch (typeof content) {
|
|
||||||
case "string":
|
|
||||||
case "number":
|
|
||||||
return content;
|
|
||||||
default:
|
|
||||||
return get(content, this.get("valueAttribute"));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
_contentForValue(value) {
|
|
||||||
return this.get("content").find(c => {
|
|
||||||
if (this._valueForContent(c) === value) { return true; }
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
_computedContentForValue(value) {
|
|
||||||
const searchedValue = value.toString();
|
|
||||||
return this.get("computedContent").find(c => {
|
return this.get("computedContent").find(c => {
|
||||||
if (c.value.toString() === searchedValue) { return true; }
|
return guidFor(c) === guid;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
_originalValueForValue(value) {
|
_filterRemovableComputedContents(computedContent) {
|
||||||
if (isNone(value)) { return null; }
|
return computedContent.filter(c => c.created === true);
|
||||||
if (value === this.noneValue) { return this.noneValue; }
|
}
|
||||||
|
|
||||||
const computedContent = this._computedContentForValue(value);
|
|
||||||
|
|
||||||
if (isNone(computedContent)) { return value; }
|
|
||||||
|
|
||||||
return get(computedContent.originalContent, this.get("valueAttribute"));
|
|
||||||
},
|
|
||||||
});
|
});
|
|
@ -0,0 +1,19 @@
|
||||||
|
{{#if category}}
|
||||||
|
{{#if hasParentCategory}}
|
||||||
|
<div class="category-status">
|
||||||
|
{{badgeForParentCategory}} {{badgeForCategory}}
|
||||||
|
<span class="topic-count">× {{topicCount}}</span>
|
||||||
|
</div>
|
||||||
|
{{else}}
|
||||||
|
<div class="category-status">
|
||||||
|
{{badgeForCategory}}
|
||||||
|
<span class="topic-count">× {{topicCount}}</span>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if hasDescription}}
|
||||||
|
<div class="category-desc">{{description}}</div>
|
||||||
|
{{/if}}
|
||||||
|
{{else}}
|
||||||
|
{{computedContent.name}}
|
||||||
|
{{/if}}
|
|
@ -0,0 +1,13 @@
|
||||||
|
{{#each icons as |icon|}} {{d-icon icon}} {{/each}}
|
||||||
|
|
||||||
|
<span class="selected-name" title={{title}}>
|
||||||
|
{{{name}}}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
{{#if shouldDisplayClearableButton}}
|
||||||
|
<button class="btn-clear" {{action onClear bubbles=false}}>
|
||||||
|
{{d-icon 'times'}}
|
||||||
|
</button>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{d-icon caretIcon class="caret-icon"}}
|
|
@ -0,0 +1,7 @@
|
||||||
|
{{#each icons as |icon|}} {{d-icon icon}} {{/each}}
|
||||||
|
|
||||||
|
{{#if options.showFullTitle}}
|
||||||
|
<span class="d-button-label selected-name">
|
||||||
|
{{name}}
|
||||||
|
</span>
|
||||||
|
{{/if}}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue