DEV: select-kit 2 (#7998)

This new iteration of select-kit focuses on following best principales and disallowing mutations inside select-kit components. A best effort has been made to avoid breaking changes, however if you content was a flat array, eg: ["foo", "bar"] You will need to set valueProperty=null and nameProperty=null on the component.

Also almost every component should have an `onChange` handler now to decide what to do with the updated data. **select-kit will not mutate your data by itself anymore**
This commit is contained in:
Joffrey JAFFEUX
2020-02-03 14:22:14 +01:00
committed by GitHub
parent 0e2cbee339
commit 0431942f3d
278 changed files with 7566 additions and 6957 deletions

View File

@ -21,13 +21,11 @@ export default Component.extend({
actions: { actions: {
penaltyChanged() { penaltyChanged() {
let postAction = this.postAction;
// If we switch to edit mode, jump to the edit textarea // If we switch to edit mode, jump to the edit textarea
if (postAction === "edit") { if (this.postAction === "edit") {
scheduleOnce("afterRender", () => { scheduleOnce("afterRender", () => {
let elem = this.element; const elem = this.element;
let body = elem.closest(".modal-body"); const body = elem.closest(".modal-body");
body.scrollTop(body.height()); body.scrollTop(body.height());
elem.querySelector(".post-editor").focus(); elem.querySelector(".post-editor").focus();
}); });

View File

@ -20,6 +20,19 @@ export default Component.extend({
]; ];
}, },
didInsertElement() {
this._super(...arguments);
schedule("afterRender", () => {
$(this.element.querySelector(".external-url")).keydown(e => {
// enter key
if (e.keyCode === 13) {
this.send("submit");
}
});
});
},
focusPermalink() { focusPermalink() {
schedule("afterRender", () => schedule("afterRender", () =>
this.element.querySelector(".permalink-url").focus() this.element.querySelector(".permalink-url").focus()
@ -64,19 +77,10 @@ export default Component.extend({
} }
); );
} }
}
}, },
didInsertElement() { onChangePermalinkType(type) {
this._super(...arguments); this.set("permalinkType", type);
schedule("afterRender", () => {
$(this.element.querySelector(".external-url")).keydown(e => {
// enter key
if (e.keyCode === 13) {
this.send("submit");
} }
});
});
} }
}); });

View File

@ -1,16 +1,15 @@
import discourseComputed from "discourse-common/utils/decorators";
import Component from "@ember/component"; import Component from "@ember/component";
import Category from "discourse/models/category"; import Category from "discourse/models/category";
import { computed } from "@ember/object";
export default Component.extend({ export default Component.extend({
@discourseComputed("value") selectedCategories: computed("value", function() {
selectedCategories: { return Category.findByIds(this.value.split("|").filter(Boolean));
get(value) { }),
return Category.findByIds(value.split("|"));
}, actions: {
set(value) { onChangeSelectedCategories(value) {
this.set("value", value.mapBy("id").join("|")); this.set("value", (value || []).mapBy("id").join("|"));
return value;
} }
} }
}); });

View File

@ -0,0 +1,43 @@
import Component from "@ember/component";
import { computed } from "@ember/object";
import { makeArray } from "discourse-common/lib/helpers";
export default Component.extend({
tokenSeparator: "|",
createdChoices: null,
settingValue: computed("value", function() {
return this.value
.toString()
.split(this.tokenSeparator)
.filter(Boolean);
}),
settingChoices: computed(
"settingValue",
"setting.choices.[]",
"createdChoices.[]",
function() {
return [
...new Set([
...makeArray(this.settingValue),
...makeArray(this.setting.choices),
...makeArray(this.createdChoices)
])
];
}
),
actions: {
onChangeListSetting(value) {
this.set("value", value.join(this.tokenSeparator));
},
onChangeChoices(choices) {
this.set("createdChoices", [
...new Set([...makeArray(this.createdChoices), ...makeArray(choices)])
]);
}
}
});

View File

@ -1,11 +1,25 @@
import discourseComputed from "discourse-common/utils/decorators"; import { computed } from "@ember/object";
import Component from "@ember/component"; import Component from "@ember/component";
export default Component.extend({ export default Component.extend({
@discourseComputed() tokenSeparator: "|",
groupChoices() {
return this.site.get("groups").map(g => { nameProperty: "name",
valueProperty: "id",
groupChoices: computed("site.groups", function() {
return (this.site.groups || []).map(g => {
return { name: g.name, id: g.id.toString() }; return { name: g.name, id: g.id.toString() };
}); });
}),
settingValue: computed("value", function() {
return (this.value || "").split(this.tokenSeparator).filter(Boolean);
}),
actions: {
onChangeGroupListSetting(value) {
this.set("value", value.join(this.tokenSeparator));
}
} }
}); });

View File

@ -1,20 +1,18 @@
import discourseComputed from "discourse-common/utils/decorators"; import discourseComputed from "discourse-common/utils/decorators";
import { makeArray } from "discourse-common/lib/helpers"; import { makeArray } from "discourse-common/lib/helpers";
import { empty, alias } from "@ember/object/computed"; import { empty, reads } from "@ember/object/computed";
import Component from "@ember/component"; import Component from "@ember/component";
import { on } from "discourse-common/utils/decorators"; import { on } from "discourse-common/utils/decorators";
export default Component.extend({ export default Component.extend({
classNameBindings: [":value-list"], classNameBindings: [":value-list"],
inputInvalid: empty("newValue"), inputInvalid: empty("newValue"),
inputDelimiter: null, inputDelimiter: null,
inputType: null, inputType: null,
newValue: "", newValue: "",
collection: null, collection: null,
values: null, values: null,
noneKey: alias("addKey"), noneKey: reads("addKey"),
@on("didReceiveAttrs") @on("didReceiveAttrs")
_setupCollection() { _setupCollection() {
@ -47,7 +45,7 @@ export default Component.extend({
addValue(newValue) { addValue(newValue) {
if (this.inputInvalid) return; if (this.inputInvalid) return;
this.set("newValue", ""); this.set("newValue", null);
this._addValue(newValue); this._addValue(newValue);
}, },
@ -62,12 +60,26 @@ export default Component.extend({
_addValue(value) { _addValue(value) {
this.collection.addObject(value); this.collection.addObject(value);
if (this.choices) {
this.set("choices", this.choices.rejectBy("id", value));
} else {
this.set("choices", []);
}
this._saveValues(); this._saveValues();
}, },
_removeValue(value) { _removeValue(value) {
const collection = this.collection; this.collection.removeObject(value);
collection.removeObject(value);
const item = { id: value, name: value };
if (this.choices) {
this.choices.addObject(item);
} else {
this.set("choices", makeArray(item));
}
this._saveValues(); this._saveValues();
}, },

View File

@ -1,5 +1,5 @@
import discourseComputed, { observes } from "discourse-common/utils/decorators"; import discourseComputed, { observes } from "discourse-common/utils/decorators";
import { alias } from "@ember/object/computed"; import { reads } from "@ember/object/computed";
import { inject } from "@ember/controller"; import { inject } from "@ember/controller";
import Controller from "@ember/controller"; import Controller from "@ember/controller";
import { popupAjaxError } from "discourse/lib/ajax-error"; import { popupAjaxError } from "discourse/lib/ajax-error";
@ -10,15 +10,37 @@ export default Controller.extend(bufferedProperty("model"), {
adminBadges: inject(), adminBadges: inject(),
saving: false, saving: false,
savingStatus: "", savingStatus: "",
badgeTypes: reads("adminBadges.badgeTypes"),
badgeTypes: alias("adminBadges.badgeTypes"), badgeGroupings: reads("adminBadges.badgeGroupings"),
badgeGroupings: alias("adminBadges.badgeGroupings"), badgeTriggers: reads("adminBadges.badgeTriggers"),
badgeTriggers: alias("adminBadges.badgeTriggers"), protectedSystemFields: reads("adminBadges.protectedSystemFields"),
protectedSystemFields: alias("adminBadges.protectedSystemFields"), readOnly: reads("buffered.system"),
readOnly: alias("buffered.system"),
showDisplayName: propertyNotEqual("name", "displayName"), showDisplayName: propertyNotEqual("name", "displayName"),
init() {
this._super(...arguments);
// this is needed because the model doesnt have default values
// and as we are using a bufferedProperty it's not accessible
// in any other way
Ember.run.next(() => {
if (!this.model.badge_type_id) {
this.model.set("badge_type_id", this.get("badgeTypes.firstObject.id"));
}
if (!this.model.badge_grouping_id) {
this.model.set(
"badge_grouping_id",
this.get("badgeGroupings.firstObject.id")
);
}
if (!this.model.trigger) {
this.model.set("trigger", this.get("badgeTriggers.firstObject.id"));
}
});
},
@discourseComputed("model.query", "buffered.query") @discourseComputed("model.query", "buffered.query")
hasQuery(modelQuery, bufferedQuery) { hasQuery(modelQuery, bufferedQuery) {
if (bufferedQuery) { if (bufferedQuery) {

View File

@ -278,7 +278,7 @@ export default Controller.extend(CanCheckEmails, {
}, },
resetCustomGroups() { resetCustomGroups() {
this.set("customGroupIdsBuffer", null); this.set("customGroupIdsBuffer", this.model.customGroups.mapBy("id"));
}, },
savePrimaryGroup() { savePrimaryGroup() {

View File

@ -5,6 +5,17 @@ import ModalFunctionality from "discourse/mixins/modal-functionality";
export default Controller.extend(ModalFunctionality, { export default Controller.extend(ModalFunctionality, {
adminCustomizeColors: inject(), adminCustomizeColors: inject(),
selectedBaseThemeId: null,
init() {
this._super(...arguments);
const defaultScheme = this.get(
"adminCustomizeColors.baseColorSchemes.0.base_scheme_id"
);
this.set("selectedBaseThemeId", defaultScheme);
},
actions: { actions: {
selectBase() { selectBase() {
this.adminCustomizeColors.send( this.adminCustomizeColors.send(

View File

@ -19,7 +19,7 @@ export default DiscourseRoute.extend({
controller.setProperties({ controller.setProperties({
originalPrimaryGroupId: model.primary_group_id, originalPrimaryGroupId: model.primary_group_id,
availableGroups: this._availableGroups, availableGroups: this._availableGroups,
customGroupIdsBuffer: null, customGroupIdsBuffer: model.customGroups.mapBy("id"),
model model
}); });
} }

View File

@ -20,7 +20,7 @@
{{/admin-form-row}} {{/admin-form-row}}
{{#admin-form-row label="admin.api.user_mode"}} {{#admin-form-row label="admin.api.user_mode"}}
{{combo-box content=userModes value=userMode onSelect=(action "changeUserMode")}} {{combo-box content=userModes value=userMode onChange=(action "changeUserMode")}}
{{/admin-form-row}} {{/admin-form-row}}
{{#if showUserSelector}} {{#if showUserSelector}}

View File

@ -23,30 +23,35 @@
<div> <div>
<label for="badge_type_id">{{i18n 'admin.badges.badge_type'}}</label> <label for="badge_type_id">{{i18n 'admin.badges.badge_type'}}</label>
{{combo-box name="badge_type_id" {{combo-box
name="badge_type_id"
value=buffered.badge_type_id value=buffered.badge_type_id
content=badgeTypes content=badgeTypes
allowInitialValueMutation=true onChange=(action (mut buffered.badge_type_id))
isDisabled=readOnly}} isDisabled=readOnly
}}
</div> </div>
<div> <div>
<label for="badge_grouping_id">{{i18n 'admin.badges.badge_grouping'}}</label> <label for="badge_grouping_id">{{i18n 'admin.badges.badge_grouping'}}</label>
<div class="badge-grouping-control"> <div class="badge-grouping-control">
{{combo-box name="badge_grouping_id" {{combo-box
name="badge_grouping_id"
value=buffered.badge_grouping_id value=buffered.badge_grouping_id
content=badgeGroupings content=badgeGroupings
class="badge-selector" class="badge-selector"
nameProperty="name"}} nameProperty="name"
onChange=(action (mut buffered.badge_grouping_id))
}}
{{d-button {{d-button
class="btn-default" class="btn-default"
action=(route-action "editGroupings") action=(route-action "editGroupings")
icon="pencil-alt"}} icon="pencil-alt"}}
}}
</div> </div>
</div> </div>
<div> <div>
<label for="description">{{i18n 'admin.badges.description'}}</label> <label for="description">{{i18n 'admin.badges.description'}}</label>
{{#if buffered.system}} {{#if buffered.system}}
@ -95,12 +100,13 @@
<div> <div>
<label for="trigger">{{i18n 'admin.badges.trigger'}}</label> <label for="trigger">{{i18n 'admin.badges.trigger'}}</label>
{{combo-box name="trigger" {{combo-box
name="trigger"
value=buffered.trigger value=buffered.trigger
content=badgeTriggers content=badgeTriggers
optionValuePath="content.id" onChange=(action (mut buffered.trigger))
optionLabelPath="content.name" disabled=readOnly
disabled=readOnly}} }}
</div> </div>
{{/if}} {{/if}}
{{/if}} {{/if}}

View File

@ -130,7 +130,10 @@
</span> </span>
<div class="input"> <div class="input">
{{date-input date=startDate onChange=(action "onChangeStartDate")}} {{date-input
date=startDate
onChange=(action "onChangeStartDate")
}}
</div> </div>
</div> </div>
@ -140,7 +143,10 @@
</span> </span>
<div class="input"> <div class="input">
{{date-input date=endDate onChange=(action "onChangeEndDate")}} {{date-input
date=endDate
onChange=(action "onChangeEndDate")
}}
</div> </div>
</div> </div>
{{/if}} {{/if}}

View File

@ -1,6 +1,10 @@
{{#if editing}} {{#if editing}}
{{#admin-form-row label="admin.user_fields.type"}} {{#admin-form-row label="admin.user_fields.type"}}
{{combo-box content=fieldTypes value=buffered.field_type}} {{combo-box
content=fieldTypes
value=buffered.field_type
onChange=(action (mut buffered.field_type))
}}
{{/admin-form-row}} {{/admin-form-row}}
{{#admin-form-row label="admin.user_fields.name"}} {{#admin-form-row label="admin.user_fields.name"}}

View File

@ -13,7 +13,11 @@
</td> </td>
<td class="editing-input"> <td class="editing-input">
<div class="label">{{i18n "admin.embedding.category"}}</div> <div class="label">{{i18n "admin.embedding.category"}}</div>
{{category-chooser value=categoryId class="small"}} {{category-chooser
value=categoryId
class="small"
onChange=(action (mut categoryId))
}}
</td> </td>
<td class="editing-controls"> <td class="editing-controls">
{{d-button icon="check" action=(action "save") class="btn-primary" disabled=cantSave}} {{d-button icon="check" action=(action "save") class="btn-primary" disabled=cantSave}}

View File

@ -4,7 +4,11 @@
{{{i18n 'admin.user.penalty_post_actions'}}} {{{i18n 'admin.user.penalty_post_actions'}}}
</div> </div>
</label> </label>
{{combo-box value=postAction content=penaltyActions onSelect=(action "penaltyChanged")}} {{combo-box
value=postAction
content=penaltyActions
onChange=(action "penaltyChanged")
}}
</div> </div>
{{#if editing}} {{#if editing}}

View File

@ -8,7 +8,11 @@
autocorrect="off" autocorrect="off"
autocapitalize="off"}} autocapitalize="off"}}
{{combo-box content=permalinkTypes value=permalinkType}} {{combo-box
content=permalinkTypes
value=permalinkType
onChange=(action (mut permalinkType))
}}
{{text-field {{text-field
value=permalink_type_value value=permalink_type_value

View File

@ -1,7 +1,5 @@
{{search-advanced-category-chooser {{search-advanced-category-chooser
filterable=true filterable=true
value=category value=category
castInteger=true onChange=(action (mut category))
onSelectNone=(action "onChange") }}
onDeselect=(action "onDeselect")
onSelect=(action "onChange")}}

View File

@ -4,5 +4,5 @@
allowAny=filter.allow_any allowAny=filter.allow_any
value=filter.default value=filter.default
none="admin.dashboard.report_filter_any" none="admin.dashboard.report_filter_any"
onSelectNone=(action "onChange") onChange=(action "onChange")
onSelect=(action "onChange")}} }}

View File

@ -1,10 +1,9 @@
{{combo-box {{combo-box
castInteger=true
filterable=true filterable=true
valueAttribute="value" valueProperty="value"
content=groupOptions content=groupOptions
value=groupId value=groupId
allowAny=filter.allow_any allowAny=filter.allow_any
none="admin.dashboard.reports.groups" none="admin.dashboard.reports.groups"
onSelectNone=(action "onChange") onChange=(action "onChange")
onSelect=(action "onChange")}} }}

View File

@ -1,4 +1,10 @@
<b>{{i18n 'admin.logs.screened_ips.form.label'}}</b> <b>{{i18n 'admin.logs.screened_ips.form.label'}}</b>
{{text-field value=ip_address disabled=formSubmitted class="ip-address-input" placeholderKey="admin.logs.screened_ips.form.ip_address" autocorrect="off" autocapitalize="off"}} {{text-field value=ip_address disabled=formSubmitted class="ip-address-input" placeholderKey="admin.logs.screened_ips.form.ip_address" autocorrect="off" autocapitalize="off"}}
{{combo-box content=actionNames value=actionName}}
{{combo-box
content=actionNames
value=actionName
onChange=(action (mut actionName))
}}
{{d-button class="btn-default" action=(action "submit") disabled=formSubmitted label="admin.logs.screened_ips.form.add"}} {{d-button class="btn-default" action=(action "submit") disabled=formSubmitted label="admin.logs.screened_ips.form.add"}}

View File

@ -1,3 +1,7 @@
{{category-selector categories=selectedCategories}} {{category-selector
categories=selectedCategories
onChange=(action "onChangeSelectedCategories")
}}
<div class='desc'>{{{unbound setting.description}}}</div> <div class='desc'>{{{unbound setting.description}}}</div>
{{setting-validation-message message=validationMessage}} {{setting-validation-message message=validationMessage}}

View File

@ -1,3 +1,7 @@
{{category-chooser value=value allowUncategorized="true"}} {{category-chooser
value=value
allowUncategorized=true
onChange=(action (mut value))
}}
{{setting-validation-message message=validationMessage}} {{setting-validation-message message=validationMessage}}
<div class='desc'>{{{unbound setting.description}}}</div> <div class='desc'>{{{unbound setting.description}}}</div>

View File

@ -1,3 +1,11 @@
{{list-setting settingValue=value choices=setting.choices settingName=setting.setting allowAny=allowAny}} {{list-setting
value=settingValue
settingName=setting.setting
allowAny=allowAny
choices=settingChoices
onChange=(action "onChangeListSetting")
onChangeChoices=(action "onChangeChoices")
}}
{{setting-validation-message message=validationMessage}} {{setting-validation-message message=validationMessage}}
<div class='desc'>{{{unbound setting.description}}}</div> <div class='desc'>{{{unbound setting.description}}}</div>

View File

@ -1,4 +1,15 @@
{{combo-box castInteger=true valueAttribute="value" content=setting.validValues value=value none=setting.allowsNone}} {{combo-box
valueProperty="value"
content=setting.validValues
value=value
onChange=(action (mut value))
allowAny=setting.allowsNone
}}
{{preview}} {{preview}}
{{setting-validation-message message=validationMessage}} {{setting-validation-message message=validationMessage}}
<div class='desc'>{{{unbound setting.description}}}</div>
<div class='desc'>
{{{unbound setting.description}}}
</div>

View File

@ -1,3 +1,10 @@
{{list-setting settingValue=value choices=groupChoices settingName='name'}} {{list-setting
value=settingValue
choices=groupChoices
settingName="name"
nameProperty=nameProperty
valueProperty=valueProperty
onChange=(action "onChangeGroupListSetting")
}}
{{setting-validation-message message=validationMessage}} {{setting-validation-message message=validationMessage}}
<div class='desc'>{{{unbound setting.description}}}</div> <div class='desc'>{{{unbound setting.description}}}</div>

View File

@ -2,12 +2,19 @@
<div class='values'> <div class='values'>
{{#each collection as |value index|}} {{#each collection as |value index|}}
<div class='value' data-index={{index}}> <div class='value' data-index={{index}}>
{{d-button action=(action "removeValue") {{d-button
action=(action "removeValue")
actionParam=value actionParam=value
icon="times" icon="times"
class="btn-default remove-value-btn btn-small"}} class="remove-value-btn btn-small"
}}
{{input title=value value=value class="value-input" focus-out=(action "changeValue" index)}} {{input
title=value
value=value
class="value-input"
focus-out=(action "changeValue" index)
}}
</div> </div>
{{/each}} {{/each}}
</div> </div>
@ -15,7 +22,10 @@
{{combo-box {{combo-box
allowAny=true allowAny=true
allowContentReplacement=true
none=noneKey none=noneKey
valueProperty=null
nameProperty=null
value=newValue
content=filteredChoices content=filteredChoices
onSelect=(action "selectChoice")}} onChange=(action "selectChoice")
}}

View File

@ -1,8 +1,8 @@
{{combo-box {{combo-box
content=sortedTemplates content=sortedTemplates
valueAttribute="id" valueProperty="id"
nameProperty="title" nameProperty="title"
onSelect=(action "selectTemplate") onChange=(action "selectTemplate")
}} }}
{{outlet}} {{outlet}}

View File

@ -30,7 +30,13 @@
{{/if}} {{/if}}
</div> </div>
{{else}} {{else}}
{{i18n "admin.logs.staff_actions.filter"}} {{combo-box content=userHistoryActions value=filterActionId none="admin.logs.staff_actions.all" onSelect=(action "filterActionIdChanged")}} {{i18n "admin.logs.staff_actions.filter"}}
{{combo-box
content=userHistoryActions
value=filterActionId
none="admin.logs.staff_actions.all"
onChange=(action "filterActionIdChanged")
}}
{{/if}} {{/if}}
{{d-button class="btn-default" action=(action "exportStaffActionLogs") label="admin.export_csv.button_text" icon="download"}} {{d-button class="btn-default" action=(action "exportStaffActionLogs") label="admin.export_csv.button_text" icon="download"}}

View File

@ -1,16 +1,20 @@
<div> <div>
{{#d-modal-body title="admin.customize.colors.select_base.title"}} {{#d-modal-body title="admin.customize.colors.select_base.title"}}
{{i18n "admin.customize.colors.select_base.description"}} {{i18n "admin.customize.colors.select_base.description"}}
{{combo-box content=model {{combo-box
content=model
value=selectedBaseThemeId value=selectedBaseThemeId
allowInitialValueMutation=true onChange=(action (mut selectedBaseThemeId))
valueAttribute="base_scheme_id"}} valueProperty="base_scheme_id"
}}
{{/d-modal-body}} {{/d-modal-body}}
<div class="modal-footer"> <div class="modal-footer">
{{d-button {{d-button
class="btn-primary" class="btn-primary"
action=(action "selectBase") action=(action "selectBase")
icon="plus" icon="plus"
label="admin.customize.new"}} label="admin.customize.new"
}}
</div> </div>
</div> </div>

View File

@ -89,7 +89,12 @@
{{input value=name placeholder=placeholder}} {{input value=name placeholder=placeholder}}
<div class="label">{{I18n "admin.customize.theme.create_type"}}</div> <div class="label">{{I18n "admin.customize.theme.create_type"}}</div>
{{combo-box valueAttribute="value" content=createTypes value=selectedType}} {{combo-box
valueProperty="value"
content=createTypes
value=selectedType
onChange=(action (mut selectedType))
}}
</div> </div>
{{/if}} {{/if}}
</div> </div>

View File

@ -8,7 +8,9 @@
label="admin.user.silence_duration" label="admin.user.silence_duration"
includeFarFuture=true includeFarFuture=true
clearable=false clearable=false
input=silenceUntil}} input=silenceUntil
onChangeInput=(action (mut silenceUntil))
}}
</label> </label>
</div> </div>

View File

@ -9,7 +9,9 @@
label="admin.user.suspend_duration" label="admin.user.suspend_duration"
includeFarFuture=true includeFarFuture=true
clearable=false clearable=false
input=suspendUntil}} input=suspendUntil
onChangeInput=(action (mut suspendUntil))
}}
</label> </label>
</div> </div>
{{suspension-details reason=reason message=message}} {{suspension-details reason=reason message=message}}

View File

@ -4,4 +4,5 @@
filters=model filters=model
reportOptions=reportOptions reportOptions=reportOptions
showFilteringUI=true showFilteringUI=true
onRefresh=(route-action "onParamsChange")}} onRefresh=(route-action "onParamsChange")
}}

View File

@ -1,6 +1,11 @@
<div class="admin-title"> <div class="admin-title">
{{period-chooser period=period}} {{period-chooser period=period onChange=(action (mut period))}}
{{combo-box content=searchTypeOptions value=searchType class='search-logs-filter'}} {{combo-box
content=searchTypeOptions
value=searchType
class="search-logs-filter"
onChange=(action (mut searchType))
}}
</div> </div>
{{#conditional-loading-spinner condition=loading}} {{#conditional-loading-spinner condition=loading}}

View File

@ -1,6 +1,11 @@
<div class="admin-title"> <div class="admin-title">
{{period-chooser period=period}} {{period-chooser period=period onChange=(action (mut period))}}
{{combo-box content=searchTypeOptions value=searchType class='search-logs-filter'}} {{combo-box
content=searchTypeOptions
value=searchType
class="search-logs-filter"
onChange=(action (mut searchType))
}}
</div> </div>
<h2> <h2>

View File

@ -16,7 +16,12 @@
<form class="form-horizontal"> <form class="form-horizontal">
<div> <div>
<label>{{i18n 'admin.badges.badge'}}</label> <label>{{i18n 'admin.badges.badge'}}</label>
{{combo-box forceEscape=true filterable=true value=selectedBadgeId content=grantableBadges}} {{combo-box
filterable=true
value=selectedBadgeId
content=grantableBadges
onChange=(action (mut selectedBadgeId))
}}
</div> </div>
<div> <div>
<label>{{i18n 'admin.badges.reason'}}</label> <label>{{i18n 'admin.badges.reason'}}</label>

View File

@ -350,8 +350,9 @@
<div class="value"> <div class="value">
{{combo-box {{combo-box
content=site.trustLevels content=site.trustLevels
value=model.trust_level
nameProperty="detailedName" nameProperty="detailedName"
value=model.trustLevel.id
onChange=(action (mut model.trust_level))
}} }}
{{#if model.dirty}} {{#if model.dirty}}
@ -514,9 +515,10 @@
<div class="field">{{i18n "admin.groups.custom"}}</div> <div class="field">{{i18n "admin.groups.custom"}}</div>
<div class="value"> <div class="value">
{{admin-group-selector {{admin-group-selector
selected=model.customGroups content=availableGroups
available=availableGroups value=customGroupIdsBuffer
buffer=customGroupIdsBuffer}} onChange=(action (mut customGroupIdsBuffer))
}}
</div> </div>
{{#if customGroupsDirty}} {{#if customGroupsDirty}}
<div class="controls"> <div class="controls">
@ -532,7 +534,9 @@
{{combo-box {{combo-box
content=model.customGroups content=model.customGroups
value=model.primary_group_id value=model.primary_group_id
none="admin.groups.no_primary"}} none="admin.groups.no_primary"
onChange=(action (mut model.primary_group_id))
}}
</div> </div>
{{#if primaryGroupDirty}} {{#if primaryGroupDirty}}
<div class="controls"> <div class="controls">

View File

@ -14,9 +14,12 @@
<div> <div>
<label for='content-type'>{{i18n 'admin.web_hooks.content_type'}}</label> <label for='content-type'>{{i18n 'admin.web_hooks.content_type'}}</label>
{{combo-box content=contentTypes {{combo-box
content=contentTypes
name="content-type" name="content-type"
value=model.content_type}} value=model.content_type
onChange=(action (mut model.content_type))
}}
</div> </div>
<div> <div>
@ -48,7 +51,10 @@
<div class='filters'> <div class='filters'>
<div class="filter"> <div class="filter">
<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}} {{category-selector
categories=model.categories
onChange=(action (mut 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>
{{#if showTagsFilter}} {{#if showTagsFilter}}

View File

@ -637,6 +637,12 @@ registerIconRenderer({
params.title params.title
).replace(/'/g, "&#39;")}'>${html}</span>`; ).replace(/'/g, "&#39;")}'>${html}</span>`;
} }
if (params.translatedtitle) {
html = `<span class="svg-icon-title" title='${params.translatedtitle.replace(
/'/g,
"&#39;"
)}'>${html}</span>`;
}
return html; return html;
}, },

View File

@ -1,13 +1,16 @@
import DropdownSelectBoxComponent from "select-kit/components/dropdown-select-box"; import DropdownSelectBoxComponent from "select-kit/components/dropdown-select-box";
import { computed } from "@ember/object";
export default DropdownSelectBoxComponent.extend({ export default DropdownSelectBoxComponent.extend({
classNames: ["auth-token-dropdown"], classNames: ["auth-token-dropdown"],
headerIcon: "wrench",
allowInitialValueMutation: false,
showFullTitle: false,
computeContent() { selectKitOptions: {
const content = [ icon: "wrench",
showFullTitle: false
},
content: computed(function() {
return [
{ {
id: "notYou", id: "notYou",
icon: "user-times", icon: "user-times",
@ -21,12 +24,10 @@ export default DropdownSelectBoxComponent.extend({
description: "" description: ""
} }
]; ];
}),
return content;
},
actions: { actions: {
onSelect(id) { onChange(id) {
switch (id) { switch (id) {
case "notYou": case "notYou":
this.showToken(this.token); this.showToken(this.token);

View File

@ -49,5 +49,22 @@ export default Component.extend(FilterModeMixin, {
noSubcategories, noSubcategories,
persistedQueryParams: params persistedQueryParams: params
}); });
},
actions: {
changeCategoryNotificationLevel(notificationLevel) {
this.category.setNotification(notificationLevel);
},
selectCategoryAdminDropdownAction(actionId) {
switch (actionId) {
case "create":
this.createCategory();
break;
case "reorder":
this.reorderCategories();
break;
}
}
} }
}); });

View File

@ -32,8 +32,9 @@ export default Component.extend({
didUpdateAttrs() { didUpdateAttrs() {
this._super(...arguments); this._super(...arguments);
if (this._picker) { if (this._picker && typeof date === "string") {
this._picker.setDate(this.date, true); const [year, month, day] = this.date.split("-").map(x => parseInt(x, 10));
this._picker.setDate(new Date(year, month - 1, day), true);
} }
}, },
@ -84,7 +85,7 @@ export default Component.extend({
this._picker && this._picker.hide(); this._picker && this._picker.hide();
if (this.onChange) { if (this.onChange) {
this.onChange(moment(value).toDate()); this.onChange(value);
} }
}, },
@ -103,5 +104,11 @@ export default Component.extend({
_opts() { _opts() {
return null; return null;
},
actions: {
onInput(event) {
this._picker && this._picker.setDate(event.target.value, true);
}
} }
}); });

View File

@ -10,7 +10,8 @@ export default DatePicker.extend({
moment() moment()
.add(1, "day") .add(1, "day")
.toDate(), .toDate(),
setDefaultDate: !!this.defaultDate setDefaultDate: !!this.defaultDate,
minDate: this.minDate || moment().toDate()
}; };
} }
}); });

View File

@ -1,4 +1,4 @@
import { next } from "@ember/runloop"; import { schedule } from "@ember/runloop";
import Component from "@ember/component"; import Component from "@ember/component";
/* global Pikaday:true */ /* global Pikaday:true */
import loadScript from "discourse/lib/load-script"; import loadScript from "discourse/lib/load-script";
@ -28,7 +28,7 @@ export default Component.extend({
_loadPikadayPicker(container) { _loadPikadayPicker(container) {
loadScript("/javascripts/pikaday.js").then(() => { loadScript("/javascripts/pikaday.js").then(() => {
next(() => { schedule("afterRender", () => {
const options = { const options = {
field: this.element.querySelector(".date-picker"), field: this.element.querySelector(".date-picker"),
container: container || null, container: container || null,

View File

@ -9,6 +9,16 @@ export default buildCategoryPanel("security", {
showPendingGroupChangesAlert: false, showPendingGroupChangesAlert: false,
interactedWithDropdowns: false, interactedWithDropdowns: false,
@on("init")
_setup() {
this.setProperties({
selectedGroup: this.get("category.availableGroups.firstObject"),
selectedPermission: this.get(
"category.availablePermissions.firstObject.id"
)
});
},
@on("init") @on("init")
_registerValidator() { _registerValidator() {
this.registerValidator(() => { this.registerValidator(() => {
@ -24,8 +34,18 @@ export default buildCategoryPanel("security", {
}, },
actions: { actions: {
onDropdownChange() { onSelectGroup(selectedGroup) {
this.set("interactedWithDropdowns", true); this.setProperties({
interactedWithDropdowns: true,
selectedGroup
});
},
onSelectPermission(selectedPermission) {
this.setProperties({
interactedWithDropdowns: true,
selectedPermission
});
}, },
editPermissions() { editPermissions() {
@ -42,11 +62,8 @@ export default buildCategoryPanel("security", {
}); });
} }
this.set(
"selectedGroup",
this.get("category.availableGroups.firstObject")
);
this.setProperties({ this.setProperties({
selectedGroup: this.get("category.availableGroups.firstObject"),
showPendingGroupChangesAlert: false, showPendingGroupChangesAlert: false,
interactedWithDropdowns: false interactedWithDropdowns: false
}); });

View File

@ -1,5 +1,5 @@
import { isEmpty } from "@ember/utils"; import { isEmpty } from "@ember/utils";
import { alias, equal, or } from "@ember/object/computed"; import { equal, or, readOnly } from "@ember/object/computed";
import { schedule } from "@ember/runloop"; import { schedule } from "@ember/runloop";
import Component from "@ember/component"; import Component from "@ember/component";
import discourseComputed, { import discourseComputed, {
@ -16,7 +16,7 @@ import {
} from "discourse/controllers/edit-topic-timer"; } from "discourse/controllers/edit-topic-timer";
export default Component.extend({ export default Component.extend({
selection: alias("topicTimer.status_type"), selection: readOnly("topicTimer.status_type"),
autoOpen: equal("selection", OPEN_STATUS_TYPE), autoOpen: equal("selection", OPEN_STATUS_TYPE),
autoClose: equal("selection", CLOSE_STATUS_TYPE), autoClose: equal("selection", CLOSE_STATUS_TYPE),
autoDelete: equal("selection", DELETE_STATUS_TYPE), autoDelete: equal("selection", DELETE_STATUS_TYPE),
@ -27,16 +27,11 @@ export default Component.extend({
@discourseComputed( @discourseComputed(
"topicTimer.updateTime", "topicTimer.updateTime",
"loading",
"publishToCategory", "publishToCategory",
"topicTimer.category_id" "topicTimer.category_id"
) )
saveDisabled(updateTime, loading, publishToCategory, topicTimerCategoryId) { saveDisabled(updateTime, publishToCategory, topicTimerCategoryId) {
return ( return isEmpty(updateTime) || (publishToCategory && !topicTimerCategoryId);
isEmpty(updateTime) ||
loading ||
(publishToCategory && !topicTimerCategoryId)
);
}, },
@discourseComputed("topic.visible") @discourseComputed("topic.visible")
@ -70,5 +65,25 @@ export default Component.extend({
this.set("topicTimer.based_on_last_post", false); this.set("topicTimer.based_on_last_post", false);
}); });
} }
},
didReceiveAttrs() {
this._super(...arguments);
// TODO: get rid of this hack
schedule("afterRender", () => {
if (!this.get("topicTimer.status_type")) {
this.set(
"topicTimer.status_type",
this.get("timerTypes.firstObject.id")
);
}
});
},
actions: {
onChangeTimerType(value) {
this.set("topicTimer.status_type", value);
}
} }
}); });

View File

@ -45,9 +45,10 @@ export default Component.extend({
const dateTime = moment(`${this.date}${time}`); const dateTime = moment(`${this.date}${time}`);
if (dateTime.isValid()) { if (dateTime.isValid()) {
this.set("input", dateTime.format(FORMAT)); this.attrs.onChangeInput &&
this.attrs.onChangeInput(dateTime.format(FORMAT));
} else { } else {
this.set("input", null); this.attrs.onChangeInput && this.attrs.onChangeInput(null);
} }
}, },
@ -109,7 +110,10 @@ export default Component.extend({
} }
if (isCustom) { if (isCustom) {
return date || time; if (date) {
return moment(`${date}${time ? " " + time : ""}`).isAfter(moment());
}
return time;
} else { } else {
return input; return input;
} }

View File

@ -1,23 +1,16 @@
import discourseComputed from "discourse-common/utils/decorators";
import DropdownSelectBoxComponent from "select-kit/components/dropdown-select-box"; import DropdownSelectBoxComponent from "select-kit/components/dropdown-select-box";
import { computed } from "@ember/object";
export default DropdownSelectBoxComponent.extend({ export default DropdownSelectBoxComponent.extend({
pluginApiIdentifiers: ["group-member-dropdown"], pluginApiIdentifiers: ["group-member-dropdown"],
classNames: "group-member-dropdown", classNames: ["group-member-dropdown"],
showFullTitle: false,
allowInitialValueMutation: false,
allowAutoSelectFirst: false,
init() { selectKitOptions: {
this._super(...arguments); icon: "wrench",
showFullTitle: false
this.headerIcon = ["wrench"];
}, },
autoHighlight() {}, content: computed("member.owner", function() {
@discourseComputed("member.owner")
content(isOwner) {
const items = [ const items = [
{ {
id: "removeMember", id: "removeMember",
@ -29,8 +22,8 @@ export default DropdownSelectBoxComponent.extend({
} }
]; ];
if (this.currentUser && this.currentUser.admin) { if (this.get("currentUser.admin")) {
if (isOwner) { if (this.member.owner) {
items.push({ items.push({
id: "removeOwner", id: "removeOwner",
name: I18n.t("groups.members.remove_owner"), name: I18n.t("groups.members.remove_owner"),
@ -52,19 +45,5 @@ export default DropdownSelectBoxComponent.extend({
} }
return items; return items;
}, })
mutateValue(id) {
switch (id) {
case "removeMember":
this.removeMember(this.member);
break;
case "makeOwner":
this.makeOwner(this.get("member.username"));
break;
case "removeOwner":
this.removeOwner(this.member);
break;
}
}
}); });

View File

@ -1,7 +1,10 @@
import discourseComputed from "discourse-common/utils/decorators"; import discourseComputed from "discourse-common/utils/decorators";
import Component from "@ember/component"; import Component from "@ember/component";
import { computed } from "@ember/object";
export default Component.extend({ export default Component.extend({
tokenSeparator: "|",
init() { init() {
this._super(...arguments); this._super(...arguments);
@ -17,6 +20,17 @@ export default Component.extend({
]; ];
}, },
groupTrustLevel: computed(
"model.grant_trust_level",
"trustLevelOptions",
function() {
return (
this.model.get("grant_trust_level") ||
this.trustLevelOptions.firstObject.value
);
}
),
@discourseComputed("model.visibility_level", "model.public_admission") @discourseComputed("model.visibility_level", "model.public_admission")
disableMembershipRequestSetting(visibility_level, publicAdmission) { disableMembershipRequestSetting(visibility_level, publicAdmission) {
visibility_level = parseInt(visibility_level, 10); visibility_level = parseInt(visibility_level, 10);
@ -30,5 +44,11 @@ export default Component.extend({
disablePublicSetting(visibility_level, allowMembershipRequests) { disablePublicSetting(visibility_level, allowMembershipRequests) {
visibility_level = parseInt(visibility_level, 10); visibility_level = parseInt(visibility_level, 10);
return allowMembershipRequests || visibility_level > 1; return allowMembershipRequests || visibility_level > 1;
},
actions: {
onChangeEmailDomainsSetting(value) {
this.set("model.emailDomains", value.join(this.tokenSeparator));
}
} }
}); });

View File

@ -0,0 +1,12 @@
export default Ember.Component.extend({
actions: {
onChange(tags) {
this.valueChanged &&
this.valueChanged({
target: {
value: tags
}
});
}
}
});

View File

@ -182,10 +182,13 @@ export default Component.extend({
.finally(() => this.set("updating", false)); .finally(() => this.set("updating", false));
}, },
categoryChanged(category) { categoryChanged(categoryId) {
let category = Category.findById(categoryId);
if (!category) { if (!category) {
category = Category.findUncategorized(); category = Category.findUncategorized();
} }
this._updates.category_id = category.id; this._updates.category_id = category.id;
}, },

View File

@ -553,7 +553,6 @@ export default Component.extend({
} }
}, },
@observes("searchedTerms.time.when", "searchedTerms.time.days")
updateSearchTermForPostTime() { updateSearchTermForPostTime() {
const match = this.filterBlocks(REGEXP_POST_TIME_PREFIX); const match = this.filterBlocks(REGEXP_POST_TIME_PREFIX);
const timeDaysFilter = this.get("searchedTerms.time.days"); const timeDaysFilter = this.get("searchedTerms.time.days");
@ -603,5 +602,28 @@ export default Component.extend({
badgeFinder(term) { badgeFinder(term) {
return Badge.findAll({ search: term }); return Badge.findAll({ search: term });
},
actions: {
onChangeWhenTime(time) {
if (time) {
this.set("searchedTerms.time.when", time);
this.updateSearchTermForPostTime();
}
},
onChangeWhenDate(date) {
if (date) {
this.set("searchedTerms.time.days", moment(date).format("YYYY-MM-DD"));
this.updateSearchTermForPostTime();
}
},
onChangeCategory(categoryId) {
if (categoryId) {
this.set("searchedTerms.category", Category.findById(categoryId));
} else {
this.set("searchedTerms.category", null);
}
}
} }
}); });

View File

@ -11,8 +11,8 @@ export default Component.extend({
}, },
actions: { actions: {
updateDestinationCategory(category) { updateDestinationCategory(categoryId) {
return this.topic.updateDestinationCategory(category.get("id")); return this.topic.updateDestinationCategory(categoryId);
}, },
publish() { publish() {

View File

@ -1,47 +1,38 @@
import DropdownSelectBoxComponent from "select-kit/components/dropdown-select-box"; import DropdownSelectBoxComponent from "select-kit/components/dropdown-select-box";
import { computed } from "@ember/object";
export default DropdownSelectBoxComponent.extend({ export default DropdownSelectBoxComponent.extend({
pluginApiIdentifiers: ["tags-admin-dropdown"], pluginApiIdentifiers: ["tags-admin-dropdown"],
classNames: "tags-admin-dropdown", classNames: "tags-admin-dropdown",
showFullTitle: false,
allowInitialValueMutation: false,
actionsMapping: null, actionsMapping: null,
init() { selectKitOptions: {
this._super(...arguments); icons: ["bars", "caret-down"],
showFullTitle: false
this.headerIcon = ["bars", "caret-down"];
}, },
autoHighlight() {}, content: computed(function() {
return [
computeContent() {
const items = [
{ {
id: "manageGroups", id: "manageGroups",
name: I18n.t("tagging.manage_groups"), name: I18n.t("tagging.manage_groups"),
description: I18n.t("tagging.manage_groups_description"), description: I18n.t("tagging.manage_groups_description"),
icon: "wrench", icon: "wrench"
__sk_row_type: "noopRow"
}, },
{ {
id: "uploadTags", id: "uploadTags",
name: I18n.t("tagging.upload"), name: I18n.t("tagging.upload"),
description: I18n.t("tagging.upload_description"), description: I18n.t("tagging.upload_description"),
icon: "upload", icon: "upload"
__sk_row_type: "noopRow"
}, },
{ {
id: "deleteUnusedTags", id: "deleteUnusedTags",
name: I18n.t("tagging.delete_unused"), name: I18n.t("tagging.delete_unused"),
description: I18n.t("tagging.delete_unused_description"), description: I18n.t("tagging.delete_unused_description"),
icon: "trash-alt", icon: "trash-alt"
__sk_row_type: "noopRow"
} }
]; ];
}),
return items;
},
actions: { actions: {
onSelect(id) { onSelect(id) {

View File

@ -17,15 +17,6 @@ export default Component.extend({
notice: null, notice: null,
showTopicTimer: null, showTopicTimer: null,
rerenderTriggers: [
"topicClosed",
"statusType",
"executeAt",
"basedOnLastPost",
"duration",
"categoryId"
],
@discourseComputed("statusType") @discourseComputed("statusType")
canRemoveTimer(type) { canRemoveTimer(type) {
if (type === REMINDER_TYPE) return true; if (type === REMINDER_TYPE) return true;
@ -38,7 +29,7 @@ export default Component.extend({
}, },
renderTopicTimer() { renderTopicTimer() {
if (!this.executeAt) { if (!this.executeAt || this.executeAt < moment()) {
this.set("showTopicTimer", null); this.set("showTopicTimer", null);
return; return;
} }
@ -50,7 +41,6 @@ export default Component.extend({
const statusUpdateAt = moment(this.executeAt); const statusUpdateAt = moment(this.executeAt);
const duration = moment.duration(statusUpdateAt - moment()); const duration = moment.duration(statusUpdateAt - moment());
const minutesLeft = duration.asMinutes(); const minutesLeft = duration.asMinutes();
if (minutesLeft > 0) { if (minutesLeft > 0) {
let rerenderDelay = 1000; let rerenderDelay = 1000;
if (minutesLeft > 2160) { if (minutesLeft > 2160) {
@ -82,9 +72,11 @@ export default Component.extend({
); );
} }
this.set("title", `${moment(this.executeAt).format("LLLL")}`.htmlSafe()); this.setProperties({
this.set("notice", `${I18n.t(this._noticeKey(), options)}`.htmlSafe()); title: `${moment(this.executeAt).format("LLLL")}`.htmlSafe(),
this.set("showTopicTimer", true); notice: `${I18n.t(this._noticeKey(), options)}`.htmlSafe(),
showTopicTimer: true
});
// TODO Sam: concerned this can cause a heavy rerender loop // TODO Sam: concerned this can cause a heavy rerender loop
if (ENV.environment !== "test") { if (ENV.environment !== "test") {

View File

@ -100,13 +100,19 @@ export default Controller.extend(ModalFunctionality, {
}); });
} }
}) })
.catch(error => { .catch(popupAjaxError)
popupAjaxError(error);
})
.finally(() => this.set("loading", false)); .finally(() => this.set("loading", false));
}, },
actions: { actions: {
onChangeStatusType(value) {
this.set("topicTimer.status_type", value);
},
onChangeUpdateTime(value) {
this.set("topicTimer.updateTime", value);
},
saveTimer() { saveTimer() {
if (!this.get("topicTimer.updateTime")) { if (!this.get("topicTimer.updateTime")) {
this.flash( this.flash(

View File

@ -86,6 +86,20 @@ export default Controller.extend({
this.toggleProperty("showActions"); this.toggleProperty("showActions");
}, },
actOnGroup(member, actionId) {
switch (actionId) {
case "removeMember":
this.send("removeMember", member);
break;
case "makeOwner":
this.send("makeOwner", member.username);
break;
case "removeOwner":
this.send("removeOwner", member);
break;
}
},
removeMember(user) { removeMember(user) {
this.model.removeMember(user, this.memberParams); this.model.removeMember(user, this.memberParams);
}, },

View File

@ -14,6 +14,7 @@ import {
isiPad, isiPad,
iOSWithVisualViewport iOSWithVisualViewport
} from "discourse/lib/utilities"; } from "discourse/lib/utilities";
import { computed } from "@ember/object";
const USER_HOMES = { const USER_HOMES = {
1: "latest", 1: "latest",
@ -76,6 +77,17 @@ export default Controller.extend(PreferencesTabController, {
}); });
}, },
homepageId: computed(
"model.user_option.homepage_id",
"userSelectableHome.[]",
function() {
return (
this.model.user_option.homepage_id ||
this.userSelectableHome.firstObject.value
);
}
),
@discourseComputed @discourseComputed
titleCountModes() { titleCountModes() {
return TITLE_COUNT_MODES.map(value => { return TITLE_COUNT_MODES.map(value => {
@ -195,6 +207,8 @@ export default Controller.extend(PreferencesTabController, {
// Force refresh when leaving this screen // Force refresh when leaving this screen
Discourse.set("assetVersion", "forceRefresh"); Discourse.set("assetVersion", "forceRefresh");
this.set("textSize", newSize);
} }
} }
}); });

View File

@ -155,9 +155,8 @@ export default Controller.extend(BulkTopicSelection, FilterModeMixin, {
}); });
}, },
changeTagNotification(id) { changeTagNotificationLevel(notificationLevel) {
const tagNotification = this.tagNotification; this.tagNotification.update({ notification_level: notificationLevel });
tagNotification.update({ notification_level: id });
} }
} }
}); });

View File

@ -242,12 +242,12 @@ export default Controller.extend(bufferedProperty("model"), {
}, },
actions: { actions: {
topicCategoryChanged(selection) { topicCategoryChanged(categoryId) {
this.set("buffered.category_id", selection.value); this.set("buffered.category_id", categoryId);
}, },
topicTagsChanged({ target }) { topicTagsChanged(value) {
this.set("buffered.tags", target.value); this.set("buffered.tags", value);
}, },
deletePending(pending) { deletePending(pending) {

View File

@ -59,6 +59,9 @@ export default Controller.extend({
}, },
actions: { actions: {
changeGroupNotificationLevel(notificationLevel) {
this.group.setNotification(notificationLevel, this.get("user.id"));
},
archive() { archive() {
this.bulkOperation("archive_messages"); this.bulkOperation("archive_messages");
}, },

View File

@ -9,7 +9,7 @@ import CanCheckEmails from "discourse/mixins/can-check-emails";
import User from "discourse/models/user"; import User from "discourse/models/user";
import optionalService from "discourse/lib/optional-service"; import optionalService from "discourse/lib/optional-service";
import { prioritizeNameInUx } from "discourse/lib/settings"; import { prioritizeNameInUx } from "discourse/lib/settings";
import { set } from "@ember/object"; import { set, computed } from "@ember/object";
export default Controller.extend(CanCheckEmails, { export default Controller.extend(CanCheckEmails, {
indexStream: false, indexStream: false,
@ -136,6 +136,21 @@ export default Controller.extend(CanCheckEmails, {
} }
}, },
userNotificationLevel: computed(
"currentUser.ignored_ids",
"model.ignored",
"model.muted",
function() {
if (this.get("model.ignored")) {
return "changeToIgnored";
} else if (this.get("model.muted")) {
return "changeToMuted";
} else {
return "changeToNormal";
}
}
),
actions: { actions: {
collapseProfile() { collapseProfile() {
this.set("forceExpand", false); this.set("forceExpand", false);

View File

@ -0,0 +1,8 @@
import { registerUnbound } from "discourse-common/lib/helpers";
registerUnbound(
"component-for-collection",
(collectionIdentifier, selectKit) => {
return selectKit.modifyComponentForCollection(collectionIdentifier);
}
);

View File

@ -0,0 +1,8 @@
import { registerUnbound } from "discourse-common/lib/helpers";
registerUnbound(
"component-for-row",
(collectionForIdentifier, item, selectKit) => {
return selectKit.modifyComponentForRow(collectionForIdentifier, item);
}
);

View File

@ -17,7 +17,7 @@ const DiscourseLocation = EmberObject.extend({
this._super(...arguments); this._super(...arguments);
this.set("location", this.location || window.location); this.set("location", this.location || window.location);
this.initState(); this.initOptions();
}, },
/** /**
@ -25,9 +25,9 @@ const DiscourseLocation = EmberObject.extend({
Used to set state on first call to setURL Used to set state on first call to setURL
@method initState @method initOptions
*/ */
initState() { initOptions() {
const history = this.history || window.history; const history = this.history || window.history;
if (history && history.scrollRestoration) { if (history && history.scrollRestoration) {
history.scrollRestoration = "manual"; history.scrollRestoration = "manual";

View File

@ -292,6 +292,10 @@ const DiscourseURL = EmberObject.extend({
return this.handleURL(path, opts); return this.handleURL(path, opts);
}, },
routeToUrl(url, opts = {}) {
this.routeTo(Discourse.getURL(url), opts);
},
rewrite(regexp, replacement, opts) { rewrite(regexp, replacement, opts) {
rewrites.push({ regexp, replacement, opts: opts || {} }); rewrites.push({ regexp, replacement, opts: opts || {} });
}, },

View File

@ -120,15 +120,14 @@ const Category = RestModel.extend({
return topicCount > (this.num_featured_topics || 2); return topicCount > (this.num_featured_topics || 2);
}, },
@discourseComputed("topic_count", "subcategories") @discourseComputed("topic_count", "subcategories.[]")
totalTopicCount(topicCount, subcats) { totalTopicCount(topicCount, subcategories) {
let count = topicCount; if (subcategories) {
if (subcats) { subcategories.forEach(subcategory => {
subcats.forEach(s => { topicCount += subcategory.topic_count;
count += s.get("topic_count");
}); });
} }
return count; return topicCount;
}, },
save() { save() {

View File

@ -12,7 +12,9 @@
{{combo-box {{combo-box
value=selectedUserBadgeId value=selectedUserBadgeId
nameProperty="badge.name" nameProperty="badge.name"
content=selectableUserBadges}} content=selectableUserBadges
onChange=(action (mut selectedUserBadgeId))
}}
</div> </div>
</div> </div>

View File

@ -2,17 +2,19 @@
{{#if breadcrumb.hasOptions}} {{#if breadcrumb.hasOptions}}
{{category-drop {{category-drop
category=breadcrumb.category category=breadcrumb.category
parentCategory=breadcrumb.parentCategory
categories=breadcrumb.options categories=breadcrumb.options
options=(hash
parentCategory=breadcrumb.parentCategory
subCategory=breadcrumb.isSubcategory subCategory=breadcrumb.isSubcategory
noSubcategories=breadcrumb.noSubcategories}} noSubcategories=breadcrumb.noSubcategories
autoFilterable=true
)
}}
{{/if}} {{/if}}
{{/each}} {{/each}}
{{#if siteSettings.tagging_enabled}} {{#if siteSettings.tagging_enabled}}
{{tag-drop {{tag-drop currentCategory=category tagId=tagId}}
currentCategory=category
tagId=tagId}}
{{/if}} {{/if}}
{{plugin-outlet name="bread-crumbs-right" connectorTagName="li" tagName=""}} {{plugin-outlet name="bread-crumbs-right" connectorTagName="li" tagName=""}}

View File

@ -3,12 +3,13 @@
{{else}} {{else}}
{{composer-actions {{composer-actions
composerModel=model composerModel=model
options=model.replyOptions replyOptions=model.replyOptions
canWhisper=canWhisper canWhisper=canWhisper
openComposer=openComposer openComposer=openComposer
closeComposer=closeComposer closeComposer=closeComposer
action=model.action action=model.action
tabindex=tabindex}} tabindex=tabindex
}}
{{/if}} {{/if}}
<span class="action-title"> <span class="action-title">

View File

@ -5,12 +5,15 @@
{{#each group.buttons as |b|}} {{#each group.buttons as |b|}}
{{#if b.popupMenu}} {{#if b.popupMenu}}
{{toolbar-popup-menu-options {{toolbar-popup-menu-options
onSelect=onPopupMenuAction content=popupMenuOptions
onChange=onPopupMenuAction
onExpand=(action b.action b) onExpand=(action b.action b)
title=b.title
headerIcon=b.icon
class=b.className class=b.className
content=popupMenuOptions}} options=(hash
popupTitle=b.title
icon=b.icon
)
}}
{{else}} {{else}}
{{d-button {{d-button
action=b.action action=b.action

View File

@ -2,14 +2,18 @@
{{#if showCategoryAdmin}} {{#if showCategoryAdmin}}
{{categories-admin-dropdown {{categories-admin-dropdown
create=createCategory onChange=(action "selectCategoryAdminDropdownAction")
reorder=reorderCategories}} }}
{{/if}} {{/if}}
{{navigation-bar navItems=navItems filterMode=filterMode category=category}} {{navigation-bar navItems=navItems filterMode=filterMode category=category}}
{{#if showCategoryNotifications}} {{#if showCategoryNotifications}}
{{category-notifications-button value=category.notification_level category=category}} {{category-notifications-button
value=category.notification_level
category=category
onChange=(action "changeCategoryNotificationLevel")
}}
{{/if}} {{/if}}
{{plugin-outlet name="before-create-topic-button" {{plugin-outlet name="before-create-topic-button"

View File

@ -2,4 +2,6 @@
type=inputType type=inputType
class="date-picker" class="date-picker"
placeholder=placeholder placeholder=placeholder
value=value}} value=value
input=(action "onInput")
}}

View File

@ -17,7 +17,9 @@
excludeCategoryId=category.id excludeCategoryId=category.id
categories=parentCategories categories=parentCategories
allowSubCategories=true allowSubCategories=true
allowUncategorized=false}} allowUncategorized=false
onChange=(action (mut category.parent_category_id))
}}
</section> </section>
{{/if}} {{/if}}

View File

@ -22,18 +22,21 @@
{{/unless}} {{/unless}}
{{#if editingPermissions}} {{#if editingPermissions}}
{{#if category.availableGroups}} {{#if category.availableGroups}}
{{combo-box class="available-groups" {{combo-box
allowInitialValueMutation=true class="available-groups"
allowContentReplacement=true
content=category.availableGroups content=category.availableGroups
onSelect=(action "onDropdownChange") onChange=(action "onSelectGroup")
value=selectedGroup}} value=selectedGroup
{{combo-box allowInitialValueMutation=true valueProperty=null
nameProperty=null
}}
{{combo-box
class="permission-selector" class="permission-selector"
nameProperty="description" nameProperty="description"
content=category.availablePermissions content=category.availablePermissions
onSelect=(action "onDropdownChange") onChange=(action "onSelectPermission")
value=selectedPermission}} value=selectedPermission
}}
{{d-button {{d-button
action=(action "addPermission" selectedGroup selectedPermission) action=(action "addPermission" selectedGroup selectedPermission)
class="btn-primary add-permission" class="btn-primary add-permission"

View File

@ -33,10 +33,13 @@
{{i18n "category.search_priority.label"}} {{i18n "category.search_priority.label"}}
</label> </label>
<div class="controls"> <div class="controls">
{{combo-box valueAttribute="value" {{combo-box
valueProperty="value"
id="category-search-priority" id="category-search-priority"
content=searchPrioritiesOptions content=searchPrioritiesOptions
value=category.search_priority}} value=category.search_priority
onChange=(action (mut category.search_priority))
}}
</div> </div>
</section> </section>
@ -145,7 +148,7 @@
{{i18n "category.default_view"}} {{i18n "category.default_view"}}
</label> </label>
<div class="controls"> <div class="controls">
{{combo-box valueAttribute="value" id="category-default-view" content=availableViews value=category.default_view}} {{combo-box valueProperty="value" id="category-default-view" content=availableViews value=category.default_view}}
</div> </div>
</section> </section>
@ -154,7 +157,7 @@
{{i18n "category.default_top_period"}} {{i18n "category.default_top_period"}}
</label> </label>
<div class="controls"> <div class="controls">
{{combo-box valueAttribute="value" id="category-default-period" content=availableTopPeriods value=category.default_top_period}} {{combo-box valueProperty="value" id="category-default-period" content=availableTopPeriods value=category.default_top_period}}
</div> </div>
</section> </section>
@ -163,9 +166,9 @@
{{i18n "category.sort_order"}} {{i18n "category.sort_order"}}
</label> </label>
<div class="controls"> <div class="controls">
{{combo-box valueAttribute="value" content=availableSorts value=category.sort_order none="category.sort_options.default"}} {{combo-box valueProperty="value" content=availableSorts value=category.sort_order none="category.sort_options.default"}}
{{#unless isDefaultSortOrder}} {{#unless isDefaultSortOrder}}
{{combo-box castBoolean=true valueAttribute="value" content=sortAscendingOptions value=category.sort_ascending none="category.sort_options.default"}} {{combo-box castBoolean=true valueProperty="value" content=sortAscendingOptions value=category.sort_ascending none="category.sort_options.default"}}
{{/unless}} {{/unless}}
</div> </div>
</section> </section>
@ -184,7 +187,7 @@
<label for="subcategory-list-style"> <label for="subcategory-list-style">
{{i18n "category.subcategory_list_style"}} {{i18n "category.subcategory_list_style"}}
</label> </label>
{{combo-box valueAttribute="value" id="subcategory-list-style" content=availableSubcategoryListStyles value=category.subcategory_list_style}} {{combo-box valueProperty="value" id="subcategory-list-style" content=availableSubcategoryListStyles value=category.subcategory_list_style}}
</section> </section>
{{/if}} {{/if}}

View File

@ -6,12 +6,17 @@
tags=category.allowed_tags tags=category.allowed_tags
everyTag=true everyTag=true
excludeSynonyms=true excludeSynonyms=true
unlimitedTagCount=true}} unlimitedTagCount=true
onChange=(action (mut category.allowed_tags))
}}
</section> </section>
<section class="field"> <section class="field">
<label for="category-allowed-tag-groups">{{i18n 'category.tags_allowed_tag_groups'}}</label> <label for="category-allowed-tag-groups">{{i18n 'category.tags_allowed_tag_groups'}}</label>
{{tag-group-chooser id="category-allowed-tag-groups" tagGroups=category.allowed_tag_groups}} {{tag-group-chooser
id="category-allowed-tag-groups"
tagGroups=category.allowed_tag_groups
}}
{{#link-to 'tagGroups'}}{{i18n 'category.manage_tag_groups_link'}}{{/link-to}} {{#link-to 'tagGroups'}}{{i18n 'category.manage_tag_groups_link'}}{{/link-to}}
</section> </section>

View File

@ -1,31 +1,42 @@
<form> <form>
<div class="control-group"> <div class="control-group">
{{combo-box class="timer-type" allowInitialValueMutation=true content=timerTypes value=selection}} {{combo-box
class="timer-type"
onChange=onChangeStatusType
content=timerTypes
value=selection
}}
</div> </div>
<div> <div>
{{#if showTimeOnly}} {{#if showTimeOnly}}
{{future-date-input {{future-date-input
input=topicTimer.updateTime input=(readonly topicTimer.updateTime)
label="topic.topic_status_update.when" label="topic.topic_status_update.when"
statusType=selection statusType=selection
includeWeekend=true includeWeekend=true
basedOnLastPost=topicTimer.based_on_last_post}} basedOnLastPost=topicTimer.based_on_last_post
onChangeInput=onChangeUpdateTime
}}
{{else if publishToCategory}} {{else if publishToCategory}}
<div class="control-group"> <div class="control-group">
<label>{{i18n 'topic.topic_status_update.publish_to'}}</label> <label>{{i18n 'topic.topic_status_update.publish_to'}}</label>
{{category-chooser {{category-chooser
value=topicTimer.category_id value=topicTimer.category_id
excludeCategoryId=excludeCategoryId}} excludeCategoryId=excludeCategoryId
onChange=(action (mut topicTimer.category_id))
}}
</div> </div>
{{future-date-input {{future-date-input
input=topicTimer.updateTime input=(readonly topicTimer.updateTime)
label="topic.topic_status_update.when" label="topic.topic_status_update.when"
statusType=selection statusType=selection
includeWeekend=true includeWeekend=true
categoryId=topicTimer.category_id categoryId=topicTimer.category_id
basedOnLastPost=topicTimer.based_on_last_post}} basedOnLastPost=topicTimer.based_on_last_post
onChangeInput=onChangeUpdateTime
}}
{{else if autoClose}} {{else if autoClose}}
{{future-date-input {{future-date-input
input=topicTimer.updateTime input=topicTimer.updateTime
@ -33,7 +44,9 @@
statusType=selection statusType=selection
includeWeekend=true includeWeekend=true
basedOnLastPost=topicTimer.based_on_last_post basedOnLastPost=topicTimer.based_on_last_post
lastPostedAt=model.last_posted_at}} lastPostedAt=model.last_posted_at
onChangeInput=onChangeUpdateTime
}}
{{/if}} {{/if}}
</div> </div>
</form> </form>

View File

@ -4,19 +4,27 @@
{{future-date-input-selector {{future-date-input-selector
minimumResultsForSearch=-1 minimumResultsForSearch=-1
statusType=statusType statusType=statusType
value=selection value=(readonly selection)
input=input input=(readonly input)
includeDateTime=includeDateTime includeDateTime=includeDateTime
includeWeekend=includeWeekend includeWeekend=includeWeekend
includeFarFuture=includeFarFuture includeFarFuture=includeFarFuture
includeMidFuture=includeMidFuture includeMidFuture=includeMidFuture
clearable=clearable clearable=clearable
none="topic.auto_update_input.none"}} none="topic.auto_update_input.none"
onChangeInput=onChangeInput
onChange=(action (mut selection))
}}
</div> </div>
{{#if displayDateAndTimePicker}} {{#if displayDateAndTimePicker}}
<div class="control-group"> <div class="control-group">
{{d-icon "calendar-alt"}} {{date-picker-future value=date defaultDate=date}} {{d-icon "calendar-alt"}}
{{date-picker-future
value=date
defaultDate=date
onSelect=(action (mut date))
}}
</div> </div>
<div class="control-group"> <div class="control-group">
@ -48,7 +56,8 @@
executeAt=executeAt executeAt=executeAt
basedOnLastPost=basedOnLastPost basedOnLastPost=basedOnLastPost
duration=duration duration=duration
categoryId=categoryId}} categoryId=categoryId
}}
</div> </div>
{{/if}} {{/if}}
</div> </div>

View File

@ -6,7 +6,10 @@
{{/link-to}} {{/link-to}}
</li> </li>
{{else}} {{else}}
{{group-dropdown content=group.extras.visible_group_names value=group.name}} {{group-dropdown
groups=group.extras.visible_group_names
value=group.name
}}
{{/if}} {{/if}}
{{#each tabs as |tab|}} {{#each tabs as |tab|}}

View File

@ -3,12 +3,15 @@
<label class="control-label">{{i18n 'admin.groups.manage.interaction.visibility'}}</label> <label class="control-label">{{i18n 'admin.groups.manage.interaction.visibility'}}</label>
<label for="visiblity">{{i18n 'admin.groups.manage.interaction.visibility_levels.title'}}</label> <label for="visiblity">{{i18n 'admin.groups.manage.interaction.visibility_levels.title'}}</label>
{{combo-box name="alias" {{combo-box
valueAttribute="value" name="alias"
valueProperty="value"
value=model.visibility_level value=model.visibility_level
content=visibilityLevelOptions content=visibilityLevelOptions
castInteger=true castInteger=true
class="groups-form-visibility-level"}} class="groups-form-visibility-level"
onChange=(action (mut model.visibility_level))
}}
<div class="control-instructions"> <div class="control-instructions">
{{i18n 'admin.groups.manage.interaction.visibility_levels.description'}} {{i18n 'admin.groups.manage.interaction.visibility_levels.description'}}
@ -19,7 +22,7 @@
<label for="visiblity">{{i18n 'admin.groups.manage.interaction.members_visibility_levels.title'}}</label> <label for="visiblity">{{i18n 'admin.groups.manage.interaction.members_visibility_levels.title'}}</label>
{{combo-box name="alias" {{combo-box name="alias"
valueAttribute="value" valueProperty="value"
value=model.members_visibility_level value=model.members_visibility_level
content=visibilityLevelOptions content=visibilityLevelOptions
castInteger=true castInteger=true
@ -35,21 +38,27 @@
<label class="control-label">{{i18n 'groups.manage.interaction.posting'}}</label> <label class="control-label">{{i18n 'groups.manage.interaction.posting'}}</label>
<label for="alias">{{i18n 'groups.alias_levels.mentionable'}}</label> <label for="alias">{{i18n 'groups.alias_levels.mentionable'}}</label>
{{combo-box name="alias" {{combo-box
valueAttribute="value" name="alias"
valueProperty="value"
value=model.mentionable_level value=model.mentionable_level
content=aliasLevelOptions content=aliasLevelOptions
class="groups-form-mentionable-level"}} class="groups-form-mentionable-level"
onChange=(action (mut model.mentionable_level))
}}
</div> </div>
<div class="control-group"> <div class="control-group">
<label for="alias">{{i18n 'groups.alias_levels.messageable'}}</label> <label for="alias">{{i18n 'groups.alias_levels.messageable'}}</label>
{{combo-box name="alias" {{combo-box
valueAttribute="value" name="alias"
valueProperty="value"
value=model.messageable_level value=model.messageable_level
content=aliasLevelOptions content=aliasLevelOptions
class="groups-form-messageable-level"}} class="groups-form-messageable-level"
onChange=(action (mut model.messageable_level))
}}
</div> </div>
<div class="control-group"> <div class="control-group">

View File

@ -6,9 +6,12 @@
{{i18n 'admin.groups.manage.membership.automatic_membership_email_domains'}} {{i18n 'admin.groups.manage.membership.automatic_membership_email_domains'}}
</label> </label>
{{list-setting name="automatic_membership" {{list-setting
name="automatic_membership"
settingValue=model.emailDomains settingValue=model.emailDomains
class="group-form-automatic-membership-automatic"}} class="group-form-automatic-membership-automatic"
onChange=(action "onChangeEmailDomainsSetting")
}}
<label> <label>
{{input type="checkbox" {{input type="checkbox"
@ -26,12 +29,14 @@
<label class="control-label">{{i18n "admin.groups.manage.membership.effects"}}</label> <label class="control-label">{{i18n "admin.groups.manage.membership.effects"}}</label>
<label for="grant_trust_level">{{i18n 'admin.groups.manage.membership.trust_levels_title'}}</label> <label for="grant_trust_level">{{i18n 'admin.groups.manage.membership.trust_levels_title'}}</label>
{{combo-box name="grant_trust_level" {{combo-box
valueAttribute="value" name="grant_trust_level"
value=model.grant_trust_level valueProperty="value"
value=groupTrustLevel
content=trustLevelOptions content=trustLevelOptions
class="groups-form-grant-trust-level"}} class="groups-form-grant-trust-level"
onChange=(action (mut model.grant_trust_level))
}}
<label> <label>
{{input type="checkbox" {{input type="checkbox"
checked=model.primary_group checked=model.primary_group

View File

@ -1,12 +1,15 @@
{{#if multiple}} {{#if multiple}}
{{dropdown-select-box {{dropdown-select-box
headerIcon=bundle.icon
class="reviewable-action-dropdown" class="reviewable-action-dropdown"
nameProperty="label" nameProperty="label"
title=bundle.label title=bundle.label
content=bundle.actions content=bundle.actions
onSelect=(action "performById") onChange=(action "performById")
disabled=reviewableUpdating}} options=(hash
icon=bundle.icon
disabled=reviewableUpdating
)
}}
{{else}} {{else}}
{{d-button {{d-button
class=(concat "reviewable-action " (dasherize first.id) " " first.button_class) class=(concat "reviewable-action " (dasherize first.id) " " first.button_class)

View File

@ -1 +1,4 @@
{{category-chooser value=value onChooseCategory=categoryChanged}} {{category-chooser
value=value
onChange=categoryChanged
}}

View File

@ -1 +1,4 @@
{{mini-tag-chooser tags=value onChangeTags=valueChanged}} {{mini-tag-chooser
value=value
onChange=(action "onChange")
}}

View File

@ -27,13 +27,13 @@
{{#each reviewable.editable_fields as |f|}} {{#each reviewable.editable_fields as |f|}}
<div class='editable-field {{dasherize f.id}}'> <div class='editable-field {{dasherize f.id}}'>
{{component {{component (concat "reviewable-field-" f.type)
(concat "reviewable-field-" f.type)
tagName='' tagName=''
value=(editable-value reviewable f.id) value=(editable-value reviewable f.id)
tagCategoryId=reviewable.category.id tagCategoryId=reviewable.category.id
valueChanged=(action "valueChanged" f.id) valueChanged=(action "valueChanged" f.id)
categoryChanged=(action "categoryChanged")}} categoryChanged=(action "categoryChanged")
}}
</div> </div>
{{/each}} {{/each}}
</div> </div>

View File

@ -15,7 +15,10 @@
<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">
{{search-advanced-category-chooser value=searchedTerms.category}} {{search-advanced-category-chooser
value=searchedTerms.category.id
onChange=(action "onChangeCategory")
}}
</div> </div>
</div> </div>
</div> </div>
@ -47,7 +50,9 @@
allowCreate=false allowCreate=false
filterPlaceholder=null filterPlaceholder=null
everyTag=true everyTag=true
unlimitedTagCount=true}} unlimitedTagCount=true
onChange=(action (mut searchedTerms.tags))
}}
<section class="field"> <section class="field">
<label>{{ input type="checkbox" class="all-tags" checked=searchedTerms.special.all_tags}} {{i18n "search.advanced.filters.all_tags"}} </label> <label>{{ input type="checkbox" class="all-tags" checked=searchedTerms.special.all_tags}} {{i18n "search.advanced.filters.all_tags"}} </label>
</section> </section>
@ -68,13 +73,27 @@
<label>{{input type="checkbox" class="in-seen" checked=searchedTerms.special.in.seen}} {{i18n "search.advanced.filters.seen"}}</label> <label>{{input type="checkbox" class="in-seen" checked=searchedTerms.special.in.seen}} {{i18n "search.advanced.filters.seen"}}</label>
</section> </section>
{{/if}} {{/if}}
{{combo-box id="in" valueAttribute="value" content=inOptions value=searchedTerms.in none="user.locale.any"}} {{combo-box
id="in"
valueProperty="value"
content=inOptions
value=searchedTerms.in
none="user.locale.any"
onChange=(action (mut searchedTerms.in))
}}
</div> </div>
</div> </div>
<div class="control-group pull-left"> <div class="control-group pull-left">
<label class="control-label" for="search-status-options">{{i18n "search.advanced.statuses.label"}}</label> <label class="control-label" for="search-status-options">{{i18n "search.advanced.statuses.label"}}</label>
<div class="controls"> <div class="controls">
{{combo-box id="status" valueAttribute="value" content=statusOptions value=searchedTerms.status none="user.locale.any"}} {{combo-box
id="status"
valueProperty="value"
content=statusOptions
value=searchedTerms.status
none="user.locale.any"
onChange=(action (mut searchedTerms.status))
}}
</div> </div>
</div> </div>
</div> </div>
@ -83,8 +102,18 @@
<div class="control-group pull-left"> <div class="control-group pull-left">
<label class="control-label" for="search-post-date">{{i18n "search.advanced.post.time.label"}}</label> <label class="control-label" for="search-post-date">{{i18n "search.advanced.post.time.label"}}</label>
<div class="controls full-search-dates"> <div class="controls full-search-dates">
{{combo-box id="postTime" valueAttribute="value" content=postTimeOptions value=searchedTerms.time.when}} {{combo-box
{{date-picker value=searchedTerms.time.days id="search-post-date"}} id="postTime"
valueProperty="value"
content=postTimeOptions
value=searchedTerms.time.when
onChange=(action "onChangeWhenTime")
}}
{{date-input
date=searchedTerms.time.days
onChange=(action "onChangeWhenDate")
id="search-post-date"
}}
</div> </div>
</div> </div>
<div class="control-group pull-left"> <div class="control-group pull-left">

View File

@ -8,7 +8,8 @@
<label>{{i18n "shared_drafts.destination_category"}}</label> <label>{{i18n "shared_drafts.destination_category"}}</label>
{{category-chooser {{category-chooser
value=topic.destination_category_id value=topic.destination_category_id
onChooseCategory=(action "updateDestinationCategory")}} onChange=(action "updateDestinationCategory")
}}
</div> </div>
<div class='publish-field'> <div class='publish-field'>

View File

@ -54,7 +54,10 @@
</div> </div>
{{#if showNotificationsButton}} {{#if showNotificationsButton}}
{{topic-notifications-button notificationLevel=topic.details.notification_level topic=topic}} {{topic-notifications-button
notificationLevel=topic.details.notification_level
topic=topic
}}
{{/if}} {{/if}}
{{plugin-outlet name="after-topic-footer-buttons" {{plugin-outlet name="after-topic-footer-buttons"

View File

@ -1,6 +1,12 @@
<label class="control-label" for="{{concat 'user-' elementId}}">{{{field.name}}} {{#if field.required}}<span class='required'>*</span>{{/if}} <label class="control-label" for="{{concat 'user-' elementId}}">{{{field.name}}} {{#if field.required}}<span class='required'>*</span>{{/if}}
</label> </label>
<div class='controls'> <div class='controls'>
{{combo-box id=(concat 'user-' elementId) content=field.options value=value none=noneLabel}} {{combo-box
id=(concat 'user-' elementId)
content=field.options
value=value
none=noneLabel
onChange=(action (mut value))
}}
<div class="instructions">{{{field.description}}}</div> <div class="instructions">{{{field.description}}}</div>
</div> </div>

View File

@ -73,16 +73,28 @@
{{#if model.showCategoryChooser}} {{#if model.showCategoryChooser}}
<div class="category-input"> <div class="category-input">
{{category-chooser {{category-chooser
fullWidthOnMobile=true
value=model.categoryId value=model.categoryId
scopedCategoryId=scopedCategoryId tabindex="3"
onChange=(action (mut model.categoryId))
isDisabled=disableCategoryChooser isDisabled=disableCategoryChooser
tabindex="3"}} options=(hash
scopedCategoryId=scopedCategoryId
)
}}
{{popup-input-tip validation=categoryValidation}} {{popup-input-tip validation=categoryValidation}}
</div> </div>
{{/if}} {{/if}}
{{#if canEditTags}} {{#if canEditTags}}
{{mini-tag-chooser tags=model.tags tabindex="4" categoryId=model.categoryId minimum=model.minimumRequiredTags isDisabled=disableTagsChooser}} {{mini-tag-chooser
value=model.tags
tabindex=4
isDisabled=disableTagsChooser
onChange=(action (mut model.tags))
options=(hash
categoryId=model.categoryId
minimum=model.minimumRequiredTags
)
}}
{{popup-input-tip validation=tagValidation}} {{popup-input-tip validation=tagValidation}}
{{/if}} {{/if}}
</div> </div>

View File

@ -55,7 +55,12 @@
<span class='desc'> <span class='desc'>
{{i18n "search.sort_by"}} {{i18n "search.sort_by"}}
</span> </span>
{{combo-box value=sortOrder content=sortOrders castInteger=true}} {{combo-box
value=sortOrder
content=sortOrders
castInteger=true
onChange=(action (mut sortOrder))
}}
</div> </div>
</div> </div>
{{/if}} {{/if}}
@ -194,12 +199,18 @@
{{#if site.mobileView}} {{#if site.mobileView}}
{{#if expanded}} {{#if expanded}}
<div class="search-advanced-filters"> <div class="search-advanced-filters">
{{search-advanced-options searchTerm=searchTerm isExpanded=expanded}} {{search-advanced-options
searchTerm=searchTerm
isExpanded=expanded
}}
</div> </div>
{{/if}} {{/if}}
{{else}} {{else}}
<div class="search-advanced-filters"> <div class="search-advanced-filters">
{{search-advanced-options searchTerm=searchTerm isExpanded=true}} {{search-advanced-options
searchTerm=searchTerm
isExpanded=true
}}
{{d-button {{d-button
label="submit" label="submit"

View File

@ -67,7 +67,9 @@
makeOwner=(action "makeOwner") makeOwner=(action "makeOwner")
removeOwner=(action "removeOwner") removeOwner=(action "removeOwner")
member=m member=m
group=model}} group=model
onChange=(action "actOnGroup" m)
}}
{{/if}} {{/if}}
{{!-- group parameter is used by plugins --}} {{!-- group parameter is used by plugins --}}
</td> </td>

View File

@ -12,12 +12,16 @@
placeholderKey="groups.index.all" placeholderKey="groups.index.all"
class="groups-header-filters-name no-blur"}} class="groups-header-filters-name no-blur"}}
{{combo-box value=type {{combo-box
value=type
content=types content=types
class="groups-header-filters-type"
onChange=(action (mut type))
options=(hash
clearable=true clearable=true
allowAutoSelectFirst=false none="groups.index.filter"
noneLabel="groups.index.filter" )
class="groups-header-filters-type"}} }}
</div> </div>
</div> </div>

View File

@ -7,9 +7,7 @@
<div class="group-members-manage"> <div class="group-members-manage">
{{#if canManageGroup}} {{#if canManageGroup}}
{{#if currentUser.admin}} {{#if currentUser.admin}}
{{group-members-dropdown {{group-members-dropdown onChange=(action "groupMembersDropdown")}}
showAddMembersModal=(route-action "showAddMembersModal")
showBulkAddModal=(route-action "showBulkAddModal")}}
{{else}} {{else}}
{{d-button {{d-button
icon="plus" icon="plus"

View File

@ -4,7 +4,7 @@
{{plugin-outlet name="users-top" connectorTagName='div' args=(hash model=model)}} {{plugin-outlet name="users-top" connectorTagName='div' args=(hash model=model)}}
<div class='clearfix user-controls'> <div class='clearfix user-controls'>
{{period-chooser period=period}} {{period-chooser period=period onChange=(action (mut period))}}
{{text-field value=nameInput placeholderKey="directory.filter_name" class="filter-name no-blur"}} {{text-field value=nameInput placeholderKey="directory.filter_name" class="filter-name no-blur"}}
</div> </div>

View File

@ -24,17 +24,17 @@
{{#if userHasTimezoneSet}} {{#if userHasTimezoneSet}}
{{#tap-tile-grid activeTile=selectedReminderType as |grid|}} {{#tap-tile-grid activeTile=selectedReminderType as |grid|}}
{{#if usingMobileDevice}} {{#if usingMobileDevice}}
<!-- {{tap-tile icon="desktop" text=(i18n "bookmarks.reminders.at_desktop") tileId=reminderTypes.AT_DESKTOP activeTile=grid.activeTile onSelect=(action "selectReminderType")}} --> <!-- {{tap-tile icon="desktop" text=(i18n "bookmarks.reminders.at_desktop") tileId=reminderTypes.AT_DESKTOP activeTile=grid.activeTile onChange=(action "selectReminderType")}} -->
{{/if}} {{/if}}
{{#if showLaterToday}} {{#if showLaterToday}}
{{tap-tile icon="far-moon" text=laterTodayFormatted tileId=reminderTypes.LATER_TODAY activeTile=grid.activeTile onSelect=(action "selectReminderType")}} {{tap-tile icon="far-moon" text=laterTodayFormatted tileId=reminderTypes.LATER_TODAY activeTile=grid.activeTile onChange=(action "selectReminderType")}}
{{/if}} {{/if}}
{{tap-tile icon="briefcase" text=nextBusinessDayFormatted tileId=reminderTypes.NEXT_BUSINESS_DAY activeTile=grid.activeTile onSelect=(action "selectReminderType")}} {{tap-tile icon="briefcase" text=nextBusinessDayFormatted tileId=reminderTypes.NEXT_BUSINESS_DAY activeTile=grid.activeTile onChange=(action "selectReminderType")}}
{{tap-tile icon="far-sun" text=tomorrowFormatted tileId=reminderTypes.TOMORROW activeTile=grid.activeTile onSelect=(action "selectReminderType")}} {{tap-tile icon="far-sun" text=tomorrowFormatted tileId=reminderTypes.TOMORROW activeTile=grid.activeTile onChange=(action "selectReminderType")}}
{{tap-tile icon="far-clock" text=nextWeekFormatted tileId=reminderTypes.NEXT_WEEK activeTile=grid.activeTile onSelect=(action "selectReminderType")}} {{tap-tile icon="far-clock" text=nextWeekFormatted tileId=reminderTypes.NEXT_WEEK activeTile=grid.activeTile onChange=(action "selectReminderType")}}
{{tap-tile icon="far-calendar-plus" text=nextMonthFormatted tileId=reminderTypes.NEXT_MONTH activeTile=grid.activeTile onSelect=(action "selectReminderType")}} {{tap-tile icon="far-calendar-plus" text=nextMonthFormatted tileId=reminderTypes.NEXT_MONTH activeTile=grid.activeTile onChange=(action "selectReminderType")}}
<!-- {{tap-tile icon="calendar-alt" text=(I18n "bookmarks.reminders.custom") tileId=reminderTypes.CUSTOM activeTile=grid.activeTile onSelect=(action "selectReminderType")}} --> <!-- {{tap-tile icon="calendar-alt" text=(I18n "bookmarks.reminders.custom") tileId=reminderTypes.CUSTOM activeTile=grid.activeTile onChange=(action "selectReminderType")}} -->
{{/tap-tile-grid}} {{/tap-tile-grid}}
{{else}} {{else}}
<div class="alert alert-info">{{{i18n "bookmarks.no_timezone" basePath=basePath }}}</div> <div class="alert alert-info">{{{i18n "bookmarks.no_timezone" basePath=basePath }}}</div>

View File

@ -1,6 +1,11 @@
<p>{{i18n "topics.bulk.choose_new_category"}}</p> <p>{{i18n "topics.bulk.choose_new_category"}}</p>
<p>{{category-chooser value=newCategoryId}}</p> <p>
{{category-chooser
value=newCategoryId
onChange=(action (mut newCategoryId))
}}
</p>
{{#conditional-loading-spinner condition=loading}} {{#conditional-loading-spinner condition=loading}}
{{d-button action=(action "changeCategory") label="topics.bulk.change_category"}} {{d-button action=(action "changeCategory") label="topics.bulk.change_category"}}

View File

@ -11,7 +11,7 @@
{{date-picker-past {{date-picker-past
value=(unbound date) value=(unbound date)
containerId="date-container" containerId="date-container"
onSelect=(action (mut date))}} onChange=(action (mut date))}}
{{input type="time" value=time}} {{input type="time" value=time}}
</form> </form>

Some files were not shown because too many files have changed in this diff Show More