DEV: Remove usage of {{action}} modifiers - Take 2 (#18476)
This PR enables the [`no-action-modifiers`](https://github.com/ember-template-lint/ember-template-lint/blob/master/docs/rule/no-action-modifiers.md) template lint rule and removes all usages of the `{{action}}` modifier in core. In general, instances of `{{action "x"}}` have been replaced with `{{on "click" (action "x")}}`. In many cases, such as for `a` elements, we also need to prevent default event handling to avoid unwanted side effects. While the `{{action}}` modifier internally calls `event.preventDefault()`, we need to handle these cases more explicitly. For this purpose, this PR also adds the [ember-event-helpers](https://github.com/buschtoens/ember-event-helpers) dependency so we can use the `prevent-default` handler. For instance: ``` <a href {{on "click" (prevent-default (action "x"))}}>Do X</a> ``` Note that `action` has not in general been refactored away as a helper yet. In general, all event handlers should be methods on the corresponding component and referenced directly (e.g. `{{on "click" this.doSomething}}`). However, the `action` helper is used extensively throughout the codebase and often references methods in the `actions` hash on controllers or routes. Thus this refactor will also be extensive and probably deserves a separate PR. Note: This work was done to complement #17767 by minimizing the potential impact of the `action` modifier override, which uses private API and arguably should be replaced with an AST transform. This is a followup to #18333, which had to be reverted because it did not account for the default treatment of modifier keys by the {{action}} modifier. Commits: * Enable `no-action-modifiers` template lint rule * Replace {{action "x"}} with {{on "click" (action "x")}} * Remove unnecessary action helper usage * Remove ctl+click tests for user-menu These tests now break in Chrome when used with addEventListener. As per the comment, they can probably be safely removed. * Prevent default event handlers to avoid unwanted side effects Uses `event.preventDefault()` in event handlers to prevent default event handling. This had been done automatically by the `action` modifier, but is not always desirable or necessary. * Restore UserCardContents#showUser action to avoid regression By keeping the `showUser` action, we can avoid a breaking change for plugins that rely upon it, while not interfering with the `showUser` argument that's been passed. * Revert EditCategoryTab#selectTab -> EditCategoryTab#select Avoid potential breaking change in themes / plugins * Restore GroupCardContents#showGroup action to avoid regression By keeping the `showGroup` action, we can avoid a breaking change for plugins that rely upon it, while not interfering with the `showGroup` argument that's been passed. * Restore SecondFactorAddTotp#showSecondFactorKey action to avoid regression By keeping the `showSecondFactorKey` action, we can avoid a breaking change for plugins that rely upon it, while not interfering with the `showSecondFactorKey` property that's maintained on the controller. * Refactor away from `actions` hash in ChooseMessage component * Modernize EmojiPicker#onCategorySelection usage * Modernize SearchResultEntry#logClick usage * Modernize Discovery::Categories#showInserted usage * Modernize Preferences::Account#resendConfirmationEmail usage * Modernize MultiSelect::SelectedCategory#onSelectedNameClick usage * Favor fn over action in SelectedChoice component * Modernize WizardStep event handlers * Favor fn over action usage in buttons * Restore Login#forgotPassword action to avoid possible regression * Introduce modKeysPressed utility Returns an array of modifier keys that are pressed during a given `MouseEvent` or `KeyboardEvent`. * Don't interfere with click events on links with `href` values when modifier keys are pressed
This commit is contained in:
parent
2559c763ad
commit
03b7b7d1bc
|
@ -3,6 +3,7 @@ module.exports = {
|
|||
extends: "discourse:recommended",
|
||||
|
||||
rules: {
|
||||
"no-action-modifiers": true,
|
||||
"no-capital-arguments": false, // TODO: we extensively use `args` argument name
|
||||
"no-curly-component-invocation": {
|
||||
allow: [
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
import Component from "@ember/component";
|
||||
import { action } from "@ember/object";
|
||||
|
||||
export default Component.extend({
|
||||
tagName: "",
|
||||
|
||||
|
@ -10,12 +12,14 @@ export default Component.extend({
|
|||
this.set("editing", false);
|
||||
},
|
||||
|
||||
actions: {
|
||||
edit() {
|
||||
this.set("buffer", this.value);
|
||||
this.toggleProperty("editing");
|
||||
},
|
||||
@action
|
||||
edit(event) {
|
||||
event?.preventDefault();
|
||||
this.set("buffer", this.value);
|
||||
this.toggleProperty("editing");
|
||||
},
|
||||
|
||||
actions: {
|
||||
save() {
|
||||
// Action has to toggle 'editing' property.
|
||||
this.action(this.buffer);
|
||||
|
|
|
@ -3,6 +3,7 @@ import I18n from "I18n";
|
|||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { fmt } from "discourse/lib/computed";
|
||||
import { isDocumentRTL } from "discourse/lib/text-direction";
|
||||
import { action } from "@ember/object";
|
||||
import { next } from "@ember/runloop";
|
||||
|
||||
export default Component.extend({
|
||||
|
@ -91,15 +92,26 @@ export default Component.extend({
|
|||
return this.theme.getError(target, fieldName);
|
||||
},
|
||||
|
||||
@action
|
||||
toggleShowAdvanced(event) {
|
||||
event?.preventDefault();
|
||||
this.toggleProperty("showAdvanced");
|
||||
},
|
||||
|
||||
@action
|
||||
toggleAddField(event) {
|
||||
event?.preventDefault();
|
||||
this.toggleProperty("addingField");
|
||||
},
|
||||
|
||||
@action
|
||||
toggleMaximize(event) {
|
||||
event?.preventDefault();
|
||||
this.toggleProperty("maximized");
|
||||
next(() => this.appEvents.trigger("ace:resize"));
|
||||
},
|
||||
|
||||
actions: {
|
||||
toggleShowAdvanced() {
|
||||
this.toggleProperty("showAdvanced");
|
||||
},
|
||||
|
||||
toggleAddField() {
|
||||
this.toggleProperty("addingField");
|
||||
},
|
||||
|
||||
cancelAddField() {
|
||||
this.set("addingField", false);
|
||||
},
|
||||
|
@ -114,11 +126,6 @@ export default Component.extend({
|
|||
this.fieldAdded(this.currentTargetName, name);
|
||||
},
|
||||
|
||||
toggleMaximize() {
|
||||
this.toggleProperty("maximized");
|
||||
next(() => this.appEvents.trigger("ace:resize"));
|
||||
},
|
||||
|
||||
onlyOverriddenChanged(value) {
|
||||
this.onlyOverriddenChanged(value);
|
||||
},
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import AdminUser from "admin/models/admin-user";
|
||||
import Component from "@ember/component";
|
||||
import EmberObject from "@ember/object";
|
||||
import EmberObject, { action } from "@ember/object";
|
||||
import I18n from "I18n";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
import copyText from "discourse/lib/copy-text";
|
||||
|
@ -21,6 +21,12 @@ export default Component.extend({
|
|||
return Math.max(visible, total);
|
||||
},
|
||||
|
||||
@action
|
||||
hide(event) {
|
||||
event?.preventDefault();
|
||||
this.set("show", false);
|
||||
},
|
||||
|
||||
actions: {
|
||||
lookup() {
|
||||
this.set("show", true);
|
||||
|
@ -55,10 +61,6 @@ export default Component.extend({
|
|||
}
|
||||
},
|
||||
|
||||
hide() {
|
||||
this.set("show", false);
|
||||
},
|
||||
|
||||
copy() {
|
||||
let text = `IP: ${this.ip}\n`;
|
||||
const location = this.location;
|
||||
|
|
|
@ -3,6 +3,7 @@ import discourseComputed from "discourse-common/utils/decorators";
|
|||
import Component from "@ember/component";
|
||||
import { escape } from "pretty-text/sanitizer";
|
||||
import { iconHTML } from "discourse-common/lib/icon-library";
|
||||
import { action } from "@ember/object";
|
||||
|
||||
const MAX_COMPONENTS = 4;
|
||||
|
||||
|
@ -59,9 +60,9 @@ export default Component.extend({
|
|||
return childrenCount - MAX_COMPONENTS;
|
||||
},
|
||||
|
||||
actions: {
|
||||
toggleChildrenExpanded() {
|
||||
this.toggleProperty("childrenExpanded");
|
||||
},
|
||||
@action
|
||||
toggleChildrenExpanded(event) {
|
||||
event?.preventDefault();
|
||||
this.toggleProperty("childrenExpanded");
|
||||
},
|
||||
});
|
||||
|
|
|
@ -133,6 +133,12 @@ export default class AdminBadgesShowController extends Controller.extend(
|
|||
this.buffered.set("image_url", null);
|
||||
}
|
||||
|
||||
@action
|
||||
showPreview(badge, explain, event) {
|
||||
event?.preventDefault();
|
||||
this.send("preview", badge, explain);
|
||||
}
|
||||
|
||||
@action
|
||||
save() {
|
||||
if (!this.saving) {
|
||||
|
|
|
@ -2,8 +2,15 @@ import AdminEmailLogsController from "admin/controllers/admin-email-logs";
|
|||
import { INPUT_DELAY } from "discourse-common/config/environment";
|
||||
import discourseDebounce from "discourse-common/lib/debounce";
|
||||
import { observes } from "discourse-common/utils/decorators";
|
||||
import { action } from "@ember/object";
|
||||
|
||||
export default AdminEmailLogsController.extend({
|
||||
@action
|
||||
handleShowIncomingEmail(id, event) {
|
||||
event?.preventDefault();
|
||||
this.send("showIncomingEmail", id);
|
||||
},
|
||||
|
||||
@observes("filter.{status,user,address,type}")
|
||||
filterEmailLogs() {
|
||||
discourseDebounce(this, this.loadLogs, INPUT_DELAY);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { empty, notEmpty, or } from "@ember/object/computed";
|
||||
import Controller from "@ember/controller";
|
||||
import EmailPreview from "admin/models/email-preview";
|
||||
import { get } from "@ember/object";
|
||||
import { action, get } from "@ember/object";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
import { inject as service } from "@ember/service";
|
||||
|
||||
|
@ -14,6 +14,12 @@ export default Controller.extend({
|
|||
showSendEmailForm: notEmpty("model.html_content"),
|
||||
htmlEmpty: empty("model.html_content"),
|
||||
|
||||
@action
|
||||
toggleShowHtml(event) {
|
||||
event?.preventDefault();
|
||||
this.toggleProperty("showHtml");
|
||||
},
|
||||
|
||||
actions: {
|
||||
updateUsername(selected) {
|
||||
this.set("username", get(selected, "firstObject"));
|
||||
|
@ -39,10 +45,6 @@ export default Controller.extend({
|
|||
});
|
||||
},
|
||||
|
||||
toggleShowHtml() {
|
||||
this.toggleProperty("showHtml");
|
||||
},
|
||||
|
||||
sendEmail() {
|
||||
this.set("sendingEmail", true);
|
||||
this.set("sentEmail", false);
|
||||
|
|
|
@ -3,6 +3,7 @@ import { INPUT_DELAY } from "discourse-common/config/environment";
|
|||
import IncomingEmail from "admin/models/incoming-email";
|
||||
import discourseDebounce from "discourse-common/lib/debounce";
|
||||
import { observes } from "discourse-common/utils/decorators";
|
||||
import { action } from "@ember/object";
|
||||
|
||||
export default AdminEmailLogsController.extend({
|
||||
@observes("filter.{status,from,to,subject,error}")
|
||||
|
@ -10,6 +11,12 @@ export default AdminEmailLogsController.extend({
|
|||
discourseDebounce(this, this.loadLogs, IncomingEmail, INPUT_DELAY);
|
||||
},
|
||||
|
||||
@action
|
||||
handleShowIncomingEmail(id, event) {
|
||||
event?.preventDefault();
|
||||
this.send("showIncomingEmail", id);
|
||||
},
|
||||
|
||||
actions: {
|
||||
loadMore() {
|
||||
this.loadLogs(IncomingEmail, true);
|
||||
|
|
|
@ -6,6 +6,7 @@ import discourseDebounce from "discourse-common/lib/debounce";
|
|||
import { exportEntity } from "discourse/lib/export-csv";
|
||||
import { observes } from "discourse-common/utils/decorators";
|
||||
import { outputExportResult } from "discourse/lib/export-result";
|
||||
import { action } from "@ember/object";
|
||||
import { inject as service } from "@ember/service";
|
||||
|
||||
export default Controller.extend({
|
||||
|
@ -26,6 +27,15 @@ export default Controller.extend({
|
|||
discourseDebounce(this, this._debouncedShow, INPUT_DELAY);
|
||||
},
|
||||
|
||||
@action
|
||||
edit(record, event) {
|
||||
event?.preventDefault();
|
||||
if (!record.get("editing")) {
|
||||
this.set("savedIpAddress", record.get("ip_address"));
|
||||
}
|
||||
record.set("editing", true);
|
||||
},
|
||||
|
||||
actions: {
|
||||
allow(record) {
|
||||
record.set("action_name", "do_nothing");
|
||||
|
@ -37,13 +47,6 @@ export default Controller.extend({
|
|||
record.save();
|
||||
},
|
||||
|
||||
edit(record) {
|
||||
if (!record.get("editing")) {
|
||||
this.set("savedIpAddress", record.get("ip_address"));
|
||||
}
|
||||
record.set("editing", true);
|
||||
},
|
||||
|
||||
cancel(record) {
|
||||
const savedIpAddress = this.savedIpAddress;
|
||||
if (savedIpAddress && record.get("editing")) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import Controller from "@ember/controller";
|
||||
import EmberObject from "@ember/object";
|
||||
import EmberObject, { action } from "@ember/object";
|
||||
import I18n from "I18n";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { exportEntity } from "discourse/lib/export-csv";
|
||||
|
@ -31,11 +31,13 @@ export default Controller.extend({
|
|||
this.set(
|
||||
"userHistoryActions",
|
||||
result.extras.user_history_actions
|
||||
.map((action) => ({
|
||||
id: action.id,
|
||||
action_id: action.action_id,
|
||||
name: I18n.t("admin.logs.staff_actions.actions." + action.id),
|
||||
name_raw: action.id,
|
||||
.map((historyAction) => ({
|
||||
id: historyAction.id,
|
||||
action_id: historyAction.action_id,
|
||||
name: I18n.t(
|
||||
"admin.logs.staff_actions.actions." + historyAction.id
|
||||
),
|
||||
name_raw: historyAction.id,
|
||||
}))
|
||||
.sort((a, b) => a.name.localeCompare(b.name))
|
||||
);
|
||||
|
@ -75,61 +77,74 @@ export default Controller.extend({
|
|||
this.scheduleRefresh();
|
||||
},
|
||||
|
||||
actions: {
|
||||
filterActionIdChanged(filterActionId) {
|
||||
if (filterActionId) {
|
||||
this.changeFilters({
|
||||
action_name: filterActionId,
|
||||
action_id: this.userHistoryActions.findBy("id", filterActionId)
|
||||
.action_id,
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
clearFilter(key) {
|
||||
if (key === "actionFilter") {
|
||||
this.set("filterActionId", null);
|
||||
this.changeFilters({
|
||||
action_name: null,
|
||||
action_id: null,
|
||||
custom_type: null,
|
||||
});
|
||||
} else {
|
||||
this.changeFilters({ [key]: null });
|
||||
}
|
||||
},
|
||||
|
||||
clearAllFilters() {
|
||||
this.set("filterActionId", null);
|
||||
this.resetFilters();
|
||||
},
|
||||
|
||||
filterByAction(logItem) {
|
||||
@action
|
||||
filterActionIdChanged(filterActionId) {
|
||||
if (filterActionId) {
|
||||
this.changeFilters({
|
||||
action_name: logItem.get("action_name"),
|
||||
action_id: logItem.get("action"),
|
||||
custom_type: logItem.get("custom_type"),
|
||||
action_name: filterActionId,
|
||||
action_id: this.userHistoryActions.findBy("id", filterActionId)
|
||||
.action_id,
|
||||
});
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
filterByStaffUser(acting_user) {
|
||||
this.changeFilters({ acting_user: acting_user.username });
|
||||
},
|
||||
@action
|
||||
clearFilter(key, event) {
|
||||
event?.preventDefault();
|
||||
if (key === "actionFilter") {
|
||||
this.set("filterActionId", null);
|
||||
this.changeFilters({
|
||||
action_name: null,
|
||||
action_id: null,
|
||||
custom_type: null,
|
||||
});
|
||||
} else {
|
||||
this.changeFilters({ [key]: null });
|
||||
}
|
||||
},
|
||||
|
||||
filterByTargetUser(target_user) {
|
||||
this.changeFilters({ target_user: target_user.username });
|
||||
},
|
||||
@action
|
||||
clearAllFilters(event) {
|
||||
event?.preventDefault();
|
||||
this.set("filterActionId", null);
|
||||
this.resetFilters();
|
||||
},
|
||||
|
||||
filterBySubject(subject) {
|
||||
this.changeFilters({ subject });
|
||||
},
|
||||
@action
|
||||
filterByAction(logItem, event) {
|
||||
event?.preventDefault();
|
||||
this.changeFilters({
|
||||
action_name: logItem.get("action_name"),
|
||||
action_id: logItem.get("action"),
|
||||
custom_type: logItem.get("custom_type"),
|
||||
});
|
||||
},
|
||||
|
||||
exportStaffActionLogs() {
|
||||
exportEntity("staff_action").then(outputExportResult);
|
||||
},
|
||||
@action
|
||||
filterByStaffUser(acting_user, event) {
|
||||
event?.preventDefault();
|
||||
this.changeFilters({ acting_user: acting_user.username });
|
||||
},
|
||||
|
||||
loadMore() {
|
||||
this.model.loadMore();
|
||||
},
|
||||
@action
|
||||
filterByTargetUser(target_user, event) {
|
||||
event?.preventDefault();
|
||||
this.changeFilters({ target_user: target_user.username });
|
||||
},
|
||||
|
||||
@action
|
||||
filterBySubject(subject, event) {
|
||||
event?.preventDefault();
|
||||
this.changeFilters({ subject });
|
||||
},
|
||||
|
||||
@action
|
||||
exportStaffActionLogs() {
|
||||
exportEntity("staff_action").then(outputExportResult);
|
||||
},
|
||||
|
||||
@action
|
||||
loadMore() {
|
||||
this.model.loadMore();
|
||||
},
|
||||
});
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import Controller from "@ember/controller";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
import { action } from "@ember/object";
|
||||
import { alias } from "@ember/object/computed";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
|
@ -43,6 +44,23 @@ export default Controller.extend({
|
|||
}
|
||||
},
|
||||
|
||||
@action
|
||||
showInserted(event) {
|
||||
event?.preventDefault();
|
||||
const webHookId = this.get("model.extras.web_hook_id");
|
||||
|
||||
ajax(`/admin/api/web_hooks/${webHookId}/events/bulk`, {
|
||||
type: "GET",
|
||||
data: { ids: this.incomingEventIds },
|
||||
}).then((data) => {
|
||||
const objects = data.map((webHookEvent) =>
|
||||
this.store.createRecord("web-hook-event", webHookEvent)
|
||||
);
|
||||
this.model.unshiftObjects(objects);
|
||||
this.set("incomingEventIds", []);
|
||||
});
|
||||
},
|
||||
|
||||
actions: {
|
||||
loadMore() {
|
||||
this.model.loadMore();
|
||||
|
@ -61,20 +79,5 @@ export default Controller.extend({
|
|||
popupAjaxError(error);
|
||||
});
|
||||
},
|
||||
|
||||
showInserted() {
|
||||
const webHookId = this.get("model.extras.web_hook_id");
|
||||
|
||||
ajax(`/admin/api/web_hooks/${webHookId}/events/bulk`, {
|
||||
type: "GET",
|
||||
data: { ids: this.incomingEventIds },
|
||||
}).then((data) => {
|
||||
const objects = data.map((event) =>
|
||||
this.store.createRecord("web-hook-event", event)
|
||||
);
|
||||
this.model.unshiftObjects(objects);
|
||||
this.set("incomingEventIds", []);
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { observes, on } from "discourse-common/utils/decorators";
|
||||
import Controller from "@ember/controller";
|
||||
import { action } from "@ember/object";
|
||||
import ModalFunctionality from "discourse/mixins/modal-functionality";
|
||||
|
||||
export default Controller.extend(ModalFunctionality, {
|
||||
|
@ -10,15 +11,17 @@ export default Controller.extend(ModalFunctionality, {
|
|||
this.set("images", value && value.length ? value.split("|") : []);
|
||||
},
|
||||
|
||||
@action
|
||||
remove(url, event) {
|
||||
event?.preventDefault();
|
||||
this.images.removeObject(url);
|
||||
},
|
||||
|
||||
actions: {
|
||||
uploadDone({ url }) {
|
||||
this.images.addObject(url);
|
||||
},
|
||||
|
||||
remove(url) {
|
||||
this.images.removeObject(url);
|
||||
},
|
||||
|
||||
close() {
|
||||
this.save(this.images.join("|"));
|
||||
this.send("closeModal");
|
||||
|
|
|
@ -88,9 +88,9 @@
|
|||
</div>
|
||||
|
||||
{{#if this.hasQuery}}
|
||||
<a href {{action "preview" this.buffered "false"}}>{{i18n "admin.badges.preview.link_text"}}</a>
|
||||
<a href {{on "click" (fn this.showPreview this.buffered "false")}}>{{i18n "admin.badges.preview.link_text"}}</a>
|
||||
|
|
||||
<a href {{action "preview" this.buffered "true"}}>{{i18n "admin.badges.preview.plan_text"}}</a>
|
||||
<a href {{on "click" (fn this.showPreview this.buffered "true")}}>{{i18n "admin.badges.preview.plan_text"}}</a>
|
||||
{{#if this.preview_loading}}
|
||||
{{i18n "loading"}}
|
||||
{{/if}}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
{{#if this.editing}}
|
||||
<TextField @value={{this.buffer}} @autofocus="autofocus" @autocomplete="off" />
|
||||
{{else}}
|
||||
<a href {{action "edit"}} class="inline-editable-field">
|
||||
<a href {{on "click" this.edit}} class="inline-editable-field">
|
||||
<span>{{this.value}}</span>
|
||||
</a>
|
||||
{{/if}}
|
||||
|
@ -11,7 +11,7 @@
|
|||
<div class="controls">
|
||||
{{#if this.editing}}
|
||||
<DButton @class="btn-default" @action={{action "save"}} @label="admin.user_fields.save" />
|
||||
<a href {{action "edit"}}>{{i18n "cancel"}}</a>
|
||||
<a href {{on "click" this.edit}}>{{i18n "cancel"}}</a>
|
||||
{{else}}
|
||||
<DButton @class="btn-default" @action={{action "edit"}} @icon="pencil-alt" />
|
||||
{{/if}}
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
|
||||
{{#if this.allowAdvanced}}
|
||||
<li>
|
||||
<a {{action "toggleShowAdvanced"}}
|
||||
<a {{on "click" this.toggleShowAdvanced}}
|
||||
href
|
||||
title={{i18n (concat "admin.customize.theme." (if this.showAdvanced "hide_advanced" "show_advanced"))}}
|
||||
class="no-text">
|
||||
|
@ -52,7 +52,7 @@
|
|||
<DButton @class="ok" @action={{action "addField" this.newFieldName}} @icon="check" />
|
||||
<DButton @class="cancel" @action={{action "cancelAddField"}} @icon="times" />
|
||||
{{else}}
|
||||
<a href {{action "toggleAddField" this.currentTargetName}} class="no-text">
|
||||
<a href {{on "click" this.toggleAddField}} class="no-text">
|
||||
{{d-icon "plus"}}
|
||||
</a>
|
||||
{{/if}}
|
||||
|
@ -61,7 +61,7 @@
|
|||
|
||||
<li class="spacer"></li>
|
||||
<li>
|
||||
<a href {{action "toggleMaximize"}} class="no-text">
|
||||
<a href {{on "click" this.toggleMaximize}} class="no-text">
|
||||
{{d-icon this.maximizeIcon}}
|
||||
</a>
|
||||
</li>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
{{/if}}
|
||||
{{#if this.show}}
|
||||
<div class="location-box">
|
||||
<a href class="close pull-right" {{action "hide"}}>{{d-icon "times"}}</a>
|
||||
<a href class="close pull-right" {{on "click" this.hide}}>{{d-icon "times"}}</a>
|
||||
{{#if this.copied}}
|
||||
<DButton @class="btn-hover pull-right" @icon="copy" @label="ip_lookup.copied" />
|
||||
{{else}}
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
<span class="components">{{html-safe this.childrenString}}</span>
|
||||
|
||||
{{#if this.displayHasMore}}
|
||||
<a href {{action "toggleChildrenExpanded"}} class="others-count">
|
||||
<a href {{on "click" this.toggleChildrenExpanded}} class="others-count">
|
||||
{{#if this.childrenExpanded}}
|
||||
{{i18n "admin.customize.theme.collapse"}}
|
||||
{{else}}
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
<td class="email-address"><a href="mailto:{{l.to_address}}">{{l.to_address}}</a></td>
|
||||
<td>
|
||||
{{#if l.has_bounce_key}}
|
||||
<a href {{action "showIncomingEmail" l.id}}>
|
||||
<a href {{on "click" (fn this.handleShowIncomingEmail l.id)}}>
|
||||
{{l.email_type}}
|
||||
</a>
|
||||
{{else}}
|
||||
|
@ -39,7 +39,7 @@
|
|||
</td>
|
||||
<td class="email-details">
|
||||
{{#if l.has_bounce_key}}
|
||||
<a href {{action "showIncomingEmail" l.id}} title={{i18n "admin.email.details_title"}}>
|
||||
<a href {{on "click" (fn this.handleShowIncomingEmail l.id)}} title={{i18n "admin.email.details_title"}}>
|
||||
{{d-icon "info-circle"}}
|
||||
</a>
|
||||
{{/if}}
|
||||
|
|
|
@ -15,11 +15,11 @@
|
|||
{{#if this.showHtml}}
|
||||
<span>{{i18n "admin.email.html"}}</span>
|
||||
|
|
||||
<a href {{action "toggleShowHtml"}}>
|
||||
<a href {{on "click" this.toggleShowHtml}}>
|
||||
{{i18n "admin.email.text"}}
|
||||
</a>
|
||||
{{else}}
|
||||
<a href {{action "toggleShowHtml"}}>{{i18n "admin.email.html"}}</a> |
|
||||
<a href {{on "click" this.toggleShowHtml}}>{{i18n "admin.email.html"}}</a> |
|
||||
<span>{{i18n "admin.email.text"}}</span>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
|
|
@ -48,10 +48,10 @@
|
|||
</td>
|
||||
<td>{{email.subject}}</td>
|
||||
<td class="error">
|
||||
<a href {{action "showIncomingEmail" email.id}}>{{email.error}}</a>
|
||||
<a href {{on "click" (fn this.handleShowIncomingEmail email.id)}}>{{email.error}}</a>
|
||||
</td>
|
||||
<td class="email-details">
|
||||
<a href {{action "showIncomingEmail" email.id}} title={{i18n "admin.email.details_title"}}>
|
||||
<a href {{on "click" (fn this.handleShowIncomingEmail email.id)}} title={{i18n "admin.email.details_title"}}>
|
||||
{{d-icon "info-circle"}}
|
||||
</a>
|
||||
</td>
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
{{#if item.editing}}
|
||||
<TextField @value={{item.ip_address}} @autofocus="autofocus" />
|
||||
{{else}}
|
||||
<a href {{action "edit" item}} class="inline-editable-field">
|
||||
<a href {{on "click" (fn this.edit item)}} class="inline-editable-field">
|
||||
{{#if item.isRange}}
|
||||
<strong>{{item.ip_address}}</strong>
|
||||
{{else}}
|
||||
|
|
|
@ -1,29 +1,29 @@
|
|||
<div class="staff-action-logs-controls">
|
||||
{{#if this.filtersExists}}
|
||||
<div class="staff-action-logs-filters">
|
||||
<a href {{action "clearAllFilters"}} class="clear-filters filter btn">
|
||||
<a href {{on "click" this.clearAllFilters}} class="clear-filters filter btn">
|
||||
<span class="label">{{i18n "admin.logs.staff_actions.clear_filters"}}</span>
|
||||
</a>
|
||||
{{#if this.actionFilter}}
|
||||
<a href {{action "clearFilter" "actionFilter"}} class="filter btn">
|
||||
<a href {{on "click" (fn this.clearFilter "actionFilter")}} class="filter btn">
|
||||
<span class="label">{{i18n "admin.logs.action"}}</span>: {{this.actionFilter}}
|
||||
{{d-icon "times-circle"}}
|
||||
</a>
|
||||
{{/if}}
|
||||
{{#if this.filters.acting_user}}
|
||||
<a href {{action "clearFilter" "acting_user"}} class="filter btn">
|
||||
<a href {{on "click" (fn this.clearFilter "acting_user")}} class="filter btn">
|
||||
<span class="label">{{i18n "admin.logs.staff_actions.staff_user"}}</span>: {{this.filters.acting_user}}
|
||||
{{d-icon "times-circle"}}
|
||||
</a>
|
||||
{{/if}}
|
||||
{{#if this.filters.target_user}}
|
||||
<a href {{action "clearFilter" "target_user"}} class="filter btn">
|
||||
<a href {{on "click" (fn this.clearFilter "target_user")}} class="filter btn">
|
||||
<span class="label">{{i18n "admin.logs.staff_actions.target_user"}}</span>: {{this.filters.target_user}}
|
||||
{{d-icon "times-circle"}}
|
||||
</a>
|
||||
{{/if}}
|
||||
{{#if this.filters.subject}}
|
||||
<a href {{action "clearFilter" "subject"}} class="filter btn">
|
||||
<a href {{on "click" (fn this.clearFilter "subject")}} class="filter btn">
|
||||
<span class="label">{{i18n "admin.logs.staff_actions.subject"}}</span>: {{this.filters.subject}}
|
||||
{{d-icon "times-circle"}}
|
||||
</a>
|
||||
|
@ -71,16 +71,16 @@
|
|||
</div>
|
||||
</td>
|
||||
<td class="col value action">
|
||||
<a href {{action "filterByAction" item}}>{{item.actionName}}</a>
|
||||
<a href {{on "click" (fn this.filterByAction item)}}>{{item.actionName}}</a>
|
||||
</td>
|
||||
<td class="col value subject">
|
||||
<div class="subject">
|
||||
{{#if item.target_user}}
|
||||
<LinkTo @route="adminUser" @model={{item.target_user}}>{{avatar item.target_user imageSize="tiny"}}</LinkTo>
|
||||
<a href {{action "filterByTargetUser" item.target_user}}>{{item.target_user.username}}</a>
|
||||
<a href {{on "click" (fn this.filterByTargetUser item.target_user)}}>{{item.target_user.username}}</a>
|
||||
{{/if}}
|
||||
{{#if item.subject}}
|
||||
<a href {{action "filterBySubject" item.subject}} title={{item.subject}}>{{item.subject}}</a>
|
||||
<a href {{on "click" (fn this.filterBySubject item.subject)}} title={{item.subject}}>{{item.subject}}</a>
|
||||
{{/if}}
|
||||
</div>
|
||||
</td>
|
||||
|
@ -89,10 +89,10 @@
|
|||
<div>
|
||||
{{html-safe item.formattedDetails}}
|
||||
{{#if item.useCustomModalForDetails}}
|
||||
<a href {{action "showCustomDetailsModal" item}}>{{d-icon "info-circle"}} {{i18n "admin.logs.staff_actions.show"}}</a>
|
||||
<a href {{on "click" (fn this.showCustomDetailsModal item)}}>{{d-icon "info-circle"}} {{i18n "admin.logs.staff_actions.show"}}</a>
|
||||
{{/if}}
|
||||
{{#if item.useModalForDetails}}
|
||||
<a href {{action "showDetailsModal" item}}>{{d-icon "info-circle"}} {{i18n "admin.logs.staff_actions.show"}}</a>
|
||||
<a href {{on "click" (fn this.showDetailsModal item)}}>{{d-icon "info-circle"}} {{i18n "admin.logs.staff_actions.show"}}</a>
|
||||
{{/if}}
|
||||
</div>
|
||||
</td>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<DModalBody @class="uploaded-image-list">
|
||||
<div class="selectable-avatars">
|
||||
{{#each this.images as |image|}}
|
||||
<a href class="selectable-avatar" {{action "remove" image}}>
|
||||
<a href class="selectable-avatar" {{on "click" (fn this.remove image)}}>
|
||||
{{bound-avatar-template image "huge"}}
|
||||
</a>
|
||||
{{else}}
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
<div class="clearfix"></div>
|
||||
</div>
|
||||
{{#if this.hasIncoming}}
|
||||
<a href tabindex="0" {{action "showInserted"}} class="alert alert-info clickable">
|
||||
<a href tabindex="0" {{on "click" this.showInserted}} class="alert alert-info clickable">
|
||||
<CountI18n @key="admin.web_hooks.events.incoming" @count={{this.incomingCount}} />
|
||||
</a>
|
||||
{{/if}}
|
||||
|
|
|
@ -50,7 +50,8 @@ export default Component.extend({
|
|||
},
|
||||
|
||||
@action
|
||||
toggleShowMuted() {
|
||||
toggleShowMuted(event) {
|
||||
event?.preventDefault();
|
||||
this.toggleProperty("showMuted");
|
||||
},
|
||||
});
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { action } from "@ember/object";
|
||||
import { alias, equal } from "@ember/object/computed";
|
||||
import discourseComputed, { observes } from "discourse-common/utils/decorators";
|
||||
import Component from "@ember/component";
|
||||
|
@ -92,11 +93,13 @@ export default Component.extend({
|
|||
this.category.updatePermission(this.group_name, type);
|
||||
},
|
||||
|
||||
actions: {
|
||||
removeRow() {
|
||||
this.category.removePermission(this.group_name);
|
||||
},
|
||||
@action
|
||||
removeRow(event) {
|
||||
event?.preventDefault();
|
||||
this.category.removePermission(this.group_name);
|
||||
},
|
||||
|
||||
actions: {
|
||||
setPermissionReply() {
|
||||
if (this.type <= PermissionType.CREATE_POST) {
|
||||
this.updatePermission(PermissionType.READONLY);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import Component from "@ember/component";
|
||||
import discourseDebounce from "discourse-common/lib/debounce";
|
||||
import { get } from "@ember/object";
|
||||
import { action, get } from "@ember/object";
|
||||
import { isEmpty } from "@ember/utils";
|
||||
import { next } from "@ember/runloop";
|
||||
import { observes } from "discourse-common/utils/decorators";
|
||||
|
@ -63,12 +63,11 @@ export default Component.extend({
|
|||
);
|
||||
},
|
||||
|
||||
actions: {
|
||||
chooseMessage(message) {
|
||||
const messageId = get(message, "id");
|
||||
this.set("selectedTopicId", messageId);
|
||||
next(() => $(`#choose-message-${messageId}`).prop("checked", "true"));
|
||||
return false;
|
||||
},
|
||||
@action
|
||||
chooseMessage(message, event) {
|
||||
event?.preventDefault();
|
||||
const messageId = get(message, "id");
|
||||
this.set("selectedTopicId", messageId);
|
||||
next(() => $(`#choose-message-${messageId}`).prop("checked", "true"));
|
||||
},
|
||||
});
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import Component from "@ember/component";
|
||||
import EmberObject from "@ember/object";
|
||||
import EmberObject, { action } from "@ember/object";
|
||||
import I18n from "I18n";
|
||||
import LinkLookup from "discourse/lib/link-lookup";
|
||||
import { not } from "@ember/object/computed";
|
||||
|
@ -54,11 +54,13 @@ export default Component.extend({
|
|||
this.set("messageCount", messages.get("length"));
|
||||
},
|
||||
|
||||
actions: {
|
||||
closeMessage(message) {
|
||||
this._removeMessage(message);
|
||||
},
|
||||
@action
|
||||
closeMessage(message, event) {
|
||||
event?.preventDefault();
|
||||
this._removeMessage(message);
|
||||
},
|
||||
|
||||
actions: {
|
||||
hideMessage(message) {
|
||||
this._removeMessage(message);
|
||||
// kind of hacky but the visibility depends on this
|
||||
|
|
|
@ -2,6 +2,7 @@ import Component from "@ember/component";
|
|||
import DiscourseURL from "discourse/lib/url";
|
||||
import I18n from "I18n";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { action } from "@ember/object";
|
||||
import { empty } from "@ember/object/computed";
|
||||
import getURL from "discourse-common/lib/get-url";
|
||||
import { propertyEqual } from "discourse/lib/computed";
|
||||
|
@ -49,13 +50,12 @@ export default Component.extend({
|
|||
return getURL(`/c/${slugPart}/edit/${this.tab}`);
|
||||
},
|
||||
|
||||
actions: {
|
||||
select() {
|
||||
this.set("selectedTab", this.tab);
|
||||
|
||||
if (!this.newCategory) {
|
||||
DiscourseURL.routeTo(this.fullSlug);
|
||||
}
|
||||
},
|
||||
@action
|
||||
select(event) {
|
||||
event?.preventDefault();
|
||||
this.set("selectedTab", this.tab);
|
||||
if (!this.newCategory) {
|
||||
DiscourseURL.routeTo(this.fullSlug);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
|
|
@ -240,7 +240,8 @@ export default Component.extend({
|
|||
},
|
||||
|
||||
@action
|
||||
onCategorySelection(sectionName) {
|
||||
onCategorySelection(sectionName, event) {
|
||||
event?.preventDefault();
|
||||
const section = document.querySelector(
|
||||
`.emoji-picker-emoji-area .section[data-section="${sectionName}"]`
|
||||
);
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { action } from "@ember/object";
|
||||
import { alias, gt } from "@ember/object/computed";
|
||||
import CardContentsBase from "discourse/mixins/card-contents-base";
|
||||
import CleansUp from "discourse/mixins/cleans-up";
|
||||
|
@ -6,6 +7,7 @@ import { Promise } from "rsvp";
|
|||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { groupPath } from "discourse/lib/url";
|
||||
import { setting } from "discourse/lib/computed";
|
||||
import { modKeysPressed } from "discourse/lib/utilities";
|
||||
|
||||
const maxMembersToDisplay = 10;
|
||||
|
||||
|
@ -70,11 +72,25 @@ export default Component.extend(CardContentsBase, CleansUp, {
|
|||
this._close();
|
||||
},
|
||||
|
||||
actions: {
|
||||
close() {
|
||||
this._close();
|
||||
},
|
||||
@action
|
||||
close(event) {
|
||||
event?.preventDefault();
|
||||
this._close();
|
||||
},
|
||||
|
||||
@action
|
||||
handleShowGroup(group, event) {
|
||||
if (event && modKeysPressed(event).length > 0) {
|
||||
return false;
|
||||
}
|
||||
event?.preventDefault();
|
||||
// Invokes `showGroup` argument. Convert to `this.args.showGroup` when
|
||||
// refactoring this to a glimmer component.
|
||||
this.showGroup(group);
|
||||
this._close();
|
||||
},
|
||||
|
||||
actions: {
|
||||
cancelFilter() {
|
||||
const postStream = this.postStream;
|
||||
postStream.cancelFilter();
|
||||
|
@ -90,8 +106,7 @@ export default Component.extend(CardContentsBase, CleansUp, {
|
|||
},
|
||||
|
||||
showGroup(group) {
|
||||
this.showGroup(group);
|
||||
this._close();
|
||||
this.handleShowGroup(group);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
|
@ -53,7 +53,8 @@ export default Component.extend({
|
|||
},
|
||||
|
||||
@action
|
||||
prefillSettings(provider) {
|
||||
prefillSettings(provider, event) {
|
||||
event?.preventDefault();
|
||||
this.form.setProperties(emailProviderDefaultSettings(provider, "imap"));
|
||||
},
|
||||
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
import Component from "@ember/component";
|
||||
import { action } from "@ember/object";
|
||||
|
||||
export default Component.extend({
|
||||
classNames: ["item"],
|
||||
|
||||
actions: {
|
||||
remove() {
|
||||
this.removeAction(this.member);
|
||||
},
|
||||
@action
|
||||
remove(event) {
|
||||
event?.preventDefault();
|
||||
this.removeAction(this.member);
|
||||
},
|
||||
});
|
||||
|
|
|
@ -43,7 +43,8 @@ export default Component.extend({
|
|||
},
|
||||
|
||||
@action
|
||||
prefillSettings(provider) {
|
||||
prefillSettings(provider, event) {
|
||||
event?.preventDefault();
|
||||
this.form.setProperties(emailProviderDefaultSettings(provider, "smtp"));
|
||||
},
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { on } from "discourse-common/utils/decorators";
|
||||
import Component from "@ember/component";
|
||||
import { action } from "@ember/object";
|
||||
import { next } from "@ember/runloop";
|
||||
import { inject as service } from "@ember/service";
|
||||
import deprecated from "discourse-common/lib/deprecated";
|
||||
|
@ -56,27 +57,27 @@ export default Component.extend({
|
|||
this.router.off("routeDidChange", this, this.currentRouteChanged);
|
||||
},
|
||||
|
||||
actions: {
|
||||
toggleExpanded() {
|
||||
this.toggleProperty("expanded");
|
||||
@action
|
||||
toggleExpanded(event) {
|
||||
event?.preventDefault();
|
||||
this.toggleProperty("expanded");
|
||||
|
||||
next(() => {
|
||||
if (this.expanded) {
|
||||
$(window)
|
||||
.off("click.mobile-nav")
|
||||
.on("click.mobile-nav", (e) => {
|
||||
if (!this.element || this.isDestroying || this.isDestroyed) {
|
||||
return;
|
||||
}
|
||||
next(() => {
|
||||
if (this.expanded) {
|
||||
$(window)
|
||||
.off("click.mobile-nav")
|
||||
.on("click.mobile-nav", (e) => {
|
||||
if (!this.element || this.isDestroying || this.isDestroyed) {
|
||||
return;
|
||||
}
|
||||
|
||||
const expander = this.element.querySelector(".expander");
|
||||
if (expander && e.target !== expander) {
|
||||
this.set("expanded", false);
|
||||
$(window).off("click.mobile-nav");
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
const expander = this.element.querySelector(".expander");
|
||||
if (expander && e.target !== expander) {
|
||||
this.set("expanded", false);
|
||||
$(window).off("click.mobile-nav");
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import discourseComputed, { observes } from "discourse-common/utils/decorators";
|
||||
import Component from "@ember/component";
|
||||
import { action } from "@ember/object";
|
||||
import DiscourseURL from "discourse/lib/url";
|
||||
import FilterModeMixin from "discourse/mixins/filter-mode";
|
||||
import { next } from "@ember/runloop";
|
||||
|
@ -61,33 +62,33 @@ export default Component.extend(FilterModeMixin, {
|
|||
DiscourseURL.appEvents.off("dom:clean", this, this.ensureDropClosed);
|
||||
},
|
||||
|
||||
actions: {
|
||||
toggleDrop() {
|
||||
this.set("expanded", !this.expanded);
|
||||
@action
|
||||
toggleDrop(event) {
|
||||
event?.preventDefault();
|
||||
this.set("expanded", !this.expanded);
|
||||
|
||||
if (this.expanded) {
|
||||
DiscourseURL.appEvents.on("dom:clean", this, this.ensureDropClosed);
|
||||
if (this.expanded) {
|
||||
DiscourseURL.appEvents.on("dom:clean", this, this.ensureDropClosed);
|
||||
|
||||
next(() => {
|
||||
if (!this.expanded) {
|
||||
return;
|
||||
}
|
||||
next(() => {
|
||||
if (!this.expanded) {
|
||||
return;
|
||||
}
|
||||
|
||||
$(this.element.querySelector(".drop a")).on("click", () => {
|
||||
this.element.querySelector(".drop").style.display = "none";
|
||||
$(this.element.querySelector(".drop a")).on("click", () => {
|
||||
this.element.querySelector(".drop").style.display = "none";
|
||||
|
||||
next(() => {
|
||||
this.ensureDropClosed();
|
||||
});
|
||||
return true;
|
||||
});
|
||||
|
||||
$(window).on("click.navigation-bar", () => {
|
||||
next(() => {
|
||||
this.ensureDropClosed();
|
||||
return true;
|
||||
});
|
||||
return true;
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
$(window).on("click.navigation-bar", () => {
|
||||
this.ensureDropClosed();
|
||||
return true;
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
|
|
|
@ -7,7 +7,7 @@ import { classify, dasherize } from "@ember/string";
|
|||
import discourseComputed, { bind } from "discourse-common/utils/decorators";
|
||||
import optionalService from "discourse/lib/optional-service";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
import { set } from "@ember/object";
|
||||
import { action, set } from "@ember/object";
|
||||
import showModal from "discourse/lib/show-modal";
|
||||
|
||||
let _components = {};
|
||||
|
@ -121,7 +121,7 @@ export default Component.extend({
|
|||
},
|
||||
|
||||
@bind
|
||||
_performConfirmed(action) {
|
||||
_performConfirmed(performableAction) {
|
||||
let reviewable = this.reviewable;
|
||||
|
||||
let performAction = () => {
|
||||
|
@ -140,7 +140,7 @@ export default Component.extend({
|
|||
});
|
||||
|
||||
return ajax(
|
||||
`/review/${reviewable.id}/perform/${action.id}?version=${version}`,
|
||||
`/review/${reviewable.id}/perform/${performableAction.id}?version=${version}`,
|
||||
{
|
||||
type: "PUT",
|
||||
data,
|
||||
|
@ -173,13 +173,16 @@ export default Component.extend({
|
|||
.finally(() => this.set("updating", false));
|
||||
};
|
||||
|
||||
if (action.client_action) {
|
||||
let actionMethod = this[`client${classify(action.client_action)}`];
|
||||
if (performableAction.client_action) {
|
||||
let actionMethod =
|
||||
this[`client${classify(performableAction.client_action)}`];
|
||||
if (actionMethod) {
|
||||
return actionMethod.call(this, reviewable, performAction);
|
||||
} else {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(`No handler for ${action.client_action} found`);
|
||||
console.error(
|
||||
`No handler for ${performableAction.client_action} found`
|
||||
);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
|
@ -209,14 +212,16 @@ export default Component.extend({
|
|||
}
|
||||
},
|
||||
|
||||
actions: {
|
||||
explainReviewable(reviewable) {
|
||||
showModal("explain-reviewable", {
|
||||
title: "review.explain.title",
|
||||
model: reviewable,
|
||||
});
|
||||
},
|
||||
@action
|
||||
explainReviewable(reviewable, event) {
|
||||
event?.preventDefault();
|
||||
showModal("explain-reviewable", {
|
||||
title: "review.explain.title",
|
||||
model: reviewable,
|
||||
});
|
||||
},
|
||||
|
||||
actions: {
|
||||
edit() {
|
||||
this.set("editing", true);
|
||||
this.set("_updates", { payload: {} });
|
||||
|
@ -259,18 +264,18 @@ export default Component.extend({
|
|||
set(this._updates, fieldId, event.target.value);
|
||||
},
|
||||
|
||||
perform(action) {
|
||||
perform(performableAction) {
|
||||
if (this.updating) {
|
||||
return;
|
||||
}
|
||||
|
||||
let msg = action.get("confirm_message");
|
||||
let requireRejectReason = action.get("require_reject_reason");
|
||||
let customModal = action.get("custom_modal");
|
||||
let msg = performableAction.get("confirm_message");
|
||||
let requireRejectReason = performableAction.get("require_reject_reason");
|
||||
let customModal = performableAction.get("custom_modal");
|
||||
if (msg) {
|
||||
bootbox.confirm(msg, (answer) => {
|
||||
if (answer) {
|
||||
return this._performConfirmed(action);
|
||||
return this._performConfirmed(performableAction);
|
||||
}
|
||||
});
|
||||
} else if (requireRejectReason) {
|
||||
|
@ -279,7 +284,7 @@ export default Component.extend({
|
|||
model: this.reviewable,
|
||||
}).setProperties({
|
||||
performConfirmed: this._performConfirmed,
|
||||
action,
|
||||
action: performableAction,
|
||||
});
|
||||
} else if (customModal) {
|
||||
showModal(customModal, {
|
||||
|
@ -287,10 +292,10 @@ export default Component.extend({
|
|||
model: this.reviewable,
|
||||
}).setProperties({
|
||||
performConfirmed: this._performConfirmed,
|
||||
action,
|
||||
action: performableAction,
|
||||
});
|
||||
} else {
|
||||
return this._performConfirmed(action);
|
||||
return this._performConfirmed(performableAction);
|
||||
}
|
||||
},
|
||||
},
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import Component from "@ember/component";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { action } from "@ember/object";
|
||||
import { gt } from "@ember/object/computed";
|
||||
import { historyHeat } from "discourse/widgets/post-edits-indicator";
|
||||
import { longDate } from "discourse/lib/formatter";
|
||||
|
@ -18,18 +19,18 @@ export default Component.extend({
|
|||
return longDate(updatedAt);
|
||||
},
|
||||
|
||||
actions: {
|
||||
showEditHistory() {
|
||||
let postId = this.get("reviewable.post_id");
|
||||
this.store.find("post", postId).then((post) => {
|
||||
let historyController = showModal("history", {
|
||||
model: post,
|
||||
modalClass: "history-modal",
|
||||
});
|
||||
historyController.refresh(postId, "latest");
|
||||
historyController.set("post", post);
|
||||
historyController.set("topicController", null);
|
||||
@action
|
||||
showEditHistory(event) {
|
||||
event?.preventDefault();
|
||||
let postId = this.get("reviewable.post_id");
|
||||
this.store.find("post", postId).then((post) => {
|
||||
let historyController = showModal("history", {
|
||||
model: post,
|
||||
modalClass: "history-modal",
|
||||
});
|
||||
},
|
||||
historyController.refresh(postId, "latest");
|
||||
historyController.set("post", post);
|
||||
historyController.set("topicController", null);
|
||||
});
|
||||
},
|
||||
});
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
import Component from "@ember/component";
|
||||
import { action } from "@ember/object";
|
||||
import showModal from "discourse/lib/show-modal";
|
||||
|
||||
export default Component.extend({
|
||||
actions: {
|
||||
showRawEmail() {
|
||||
showModal("raw-email").set("rawEmail", this.reviewable.payload.raw_email);
|
||||
},
|
||||
@action
|
||||
showRawEmail(event) {
|
||||
event?.preventDefault();
|
||||
showModal("raw-email").set("rawEmail", this.reviewable.payload.raw_email);
|
||||
},
|
||||
});
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import Component from "@ember/component";
|
||||
import { action } from "@ember/object";
|
||||
import { logSearchLinkClick } from "discourse/lib/search";
|
||||
import { modKeysPressed } from "discourse/lib/utilities";
|
||||
|
||||
export default Component.extend({
|
||||
tagName: "div",
|
||||
|
@ -10,7 +11,11 @@ export default Component.extend({
|
|||
role: "listitem",
|
||||
|
||||
@action
|
||||
logClick(topicId) {
|
||||
logClick(topicId, event) {
|
||||
// Avoid click logging when any modifier keys are pressed.
|
||||
if (event && modKeysPressed(event).length > 0) {
|
||||
return false;
|
||||
}
|
||||
if (this.searchLogId && topicId) {
|
||||
logSearchLinkClick({
|
||||
searchLogId: this.searchLogId,
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import Component from "@ember/component";
|
||||
import { action } from "@ember/object";
|
||||
import I18n from "I18n";
|
||||
import { SECOND_FACTOR_METHODS } from "discourse/models/user";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
|
@ -48,15 +49,15 @@ export default Component.extend({
|
|||
);
|
||||
},
|
||||
|
||||
actions: {
|
||||
toggleSecondFactorMethod() {
|
||||
const secondFactorMethod = this.secondFactorMethod;
|
||||
this.set("secondFactorToken", "");
|
||||
if (secondFactorMethod === SECOND_FACTOR_METHODS.TOTP) {
|
||||
this.set("secondFactorMethod", SECOND_FACTOR_METHODS.BACKUP_CODE);
|
||||
} else {
|
||||
this.set("secondFactorMethod", SECOND_FACTOR_METHODS.TOTP);
|
||||
}
|
||||
},
|
||||
@action
|
||||
toggleSecondFactorMethod(event) {
|
||||
event?.preventDefault();
|
||||
const secondFactorMethod = this.secondFactorMethod;
|
||||
this.set("secondFactorToken", "");
|
||||
if (secondFactorMethod === SECOND_FACTOR_METHODS.TOTP) {
|
||||
this.set("secondFactorMethod", SECOND_FACTOR_METHODS.BACKUP_CODE);
|
||||
} else {
|
||||
this.set("secondFactorMethod", SECOND_FACTOR_METHODS.TOTP);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
import Component from "@ember/component";
|
||||
import { action } from "@ember/object";
|
||||
import { SECOND_FACTOR_METHODS } from "discourse/models/user";
|
||||
|
||||
export default Component.extend({
|
||||
actions: {
|
||||
useAnotherMethod() {
|
||||
this.set("showSecurityKey", false);
|
||||
this.set("showSecondFactor", true);
|
||||
this.set("secondFactorMethod", SECOND_FACTOR_METHODS.TOTP);
|
||||
},
|
||||
@action
|
||||
useAnotherMethod(event) {
|
||||
event?.preventDefault();
|
||||
this.set("showSecurityKey", false);
|
||||
this.set("showSecondFactor", true);
|
||||
this.set("secondFactorMethod", SECOND_FACTOR_METHODS.TOTP);
|
||||
},
|
||||
});
|
||||
|
|
|
@ -1,15 +1,19 @@
|
|||
import Component from "@ember/component";
|
||||
import discourseLater from "discourse-common/lib/later";
|
||||
import { action } from "@ember/object";
|
||||
import { on } from "@ember/object/evented";
|
||||
|
||||
export default Component.extend({
|
||||
action: "showCreateAccount",
|
||||
|
||||
@action
|
||||
neverShow(event) {
|
||||
event?.preventDefault();
|
||||
this.keyValueStore.setItem("anon-cta-never", "t");
|
||||
this.session.set("showSignupCta", false);
|
||||
},
|
||||
|
||||
actions: {
|
||||
neverShow() {
|
||||
this.keyValueStore.setItem("anon-cta-never", "t");
|
||||
this.session.set("showSignupCta", false);
|
||||
},
|
||||
hideForSession() {
|
||||
this.session.set("hideSignupCta", true);
|
||||
this.keyValueStore.setItem("anon-cta-hidden", Date.now());
|
||||
|
|
|
@ -7,6 +7,7 @@ import discourseComputed from "discourse-common/utils/decorators";
|
|||
import { isEmpty } from "@ember/utils";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
import { inject as service } from "@ember/service";
|
||||
import { action } from "@ember/object";
|
||||
|
||||
export default Component.extend({
|
||||
dialog: service(),
|
||||
|
@ -76,19 +77,49 @@ export default Component.extend({
|
|||
.catch(popupAjaxError);
|
||||
},
|
||||
|
||||
@action
|
||||
edit(event) {
|
||||
event?.preventDefault();
|
||||
this.setProperties({
|
||||
editing: true,
|
||||
newTagName: this.tag.id,
|
||||
newTagDescription: this.tagInfo.description,
|
||||
});
|
||||
},
|
||||
|
||||
@action
|
||||
unlinkSynonym(tag, event) {
|
||||
event?.preventDefault();
|
||||
ajax(`/tag/${this.tagInfo.name}/synonyms/${tag.id}`, {
|
||||
type: "DELETE",
|
||||
})
|
||||
.then(() => this.tagInfo.synonyms.removeObject(tag))
|
||||
.catch(popupAjaxError);
|
||||
},
|
||||
|
||||
@action
|
||||
deleteSynonym(tag, event) {
|
||||
event?.preventDefault();
|
||||
bootbox.confirm(
|
||||
I18n.t("tagging.delete_synonym_confirm", { tag_name: tag.text }),
|
||||
(result) => {
|
||||
if (!result) {
|
||||
return;
|
||||
}
|
||||
|
||||
tag
|
||||
.destroyRecord()
|
||||
.then(() => this.tagInfo.synonyms.removeObject(tag))
|
||||
.catch(popupAjaxError);
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
actions: {
|
||||
toggleEditControls() {
|
||||
this.toggleProperty("showEditControls");
|
||||
},
|
||||
|
||||
edit() {
|
||||
this.setProperties({
|
||||
editing: true,
|
||||
newTagName: this.tag.id,
|
||||
newTagDescription: this.tagInfo.description,
|
||||
});
|
||||
},
|
||||
|
||||
cancelEditing() {
|
||||
this.set("editing", false);
|
||||
},
|
||||
|
@ -114,30 +145,6 @@ export default Component.extend({
|
|||
this.deleteAction(this.tagInfo);
|
||||
},
|
||||
|
||||
unlinkSynonym(tag) {
|
||||
ajax(`/tag/${this.tagInfo.name}/synonyms/${tag.id}`, {
|
||||
type: "DELETE",
|
||||
})
|
||||
.then(() => this.tagInfo.synonyms.removeObject(tag))
|
||||
.catch(popupAjaxError);
|
||||
},
|
||||
|
||||
deleteSynonym(tag) {
|
||||
bootbox.confirm(
|
||||
I18n.t("tagging.delete_synonym_confirm", { tag_name: tag.text }),
|
||||
(result) => {
|
||||
if (!result) {
|
||||
return;
|
||||
}
|
||||
|
||||
tag
|
||||
.destroyRecord()
|
||||
.then(() => this.tagInfo.synonyms.removeObject(tag))
|
||||
.catch(popupAjaxError);
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
addSynonyms() {
|
||||
bootbox.confirm(
|
||||
I18n.t("tagging.add_synonyms_explanation", {
|
||||
|
|
|
@ -251,6 +251,7 @@ export default Component.extend({
|
|||
if (wantsNewWindow(e)) {
|
||||
return true;
|
||||
}
|
||||
e.preventDefault();
|
||||
return this.navigateToTopic(topic, e.target.getAttribute("href"));
|
||||
}
|
||||
|
||||
|
@ -264,6 +265,7 @@ export default Component.extend({
|
|||
if (wantsNewWindow(e)) {
|
||||
return true;
|
||||
}
|
||||
e.preventDefault();
|
||||
return this.navigateToTopic(topic, topic.lastUnreadUrl);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import EmberObject, { set } from "@ember/object";
|
||||
import EmberObject, { action, set } from "@ember/object";
|
||||
import { alias, and, gt, gte, not, or } from "@ember/object/computed";
|
||||
import discourseComputed, { observes } from "discourse-common/utils/decorators";
|
||||
import { propertyNotEqual, setting } from "discourse/lib/computed";
|
||||
|
@ -14,7 +14,7 @@ import { isEmpty } from "@ember/utils";
|
|||
import { prioritizeNameInUx } from "discourse/lib/settings";
|
||||
import { dasherize } from "@ember/string";
|
||||
import { emojiUnescape } from "discourse/lib/text";
|
||||
import { escapeExpression } from "discourse/lib/utilities";
|
||||
import { escapeExpression, modKeysPressed } from "discourse/lib/utilities";
|
||||
|
||||
export default Component.extend(CardContentsBase, CanCheckEmails, CleansUp, {
|
||||
elementId: "user-card",
|
||||
|
@ -220,6 +220,18 @@ export default Component.extend(CardContentsBase, CanCheckEmails, CleansUp, {
|
|||
this._close();
|
||||
},
|
||||
|
||||
@action
|
||||
handleShowUser(user, event) {
|
||||
if (event && modKeysPressed(event).length > 0) {
|
||||
return false;
|
||||
}
|
||||
event?.preventDefault();
|
||||
// Invokes `showUser` argument. Convert to `this.args.showUser` when
|
||||
// refactoring this to a glimmer component.
|
||||
this.showUser(user);
|
||||
this._close();
|
||||
},
|
||||
|
||||
actions: {
|
||||
close() {
|
||||
this._close();
|
||||
|
@ -247,9 +259,8 @@ export default Component.extend(CardContentsBase, CanCheckEmails, CleansUp, {
|
|||
this._close();
|
||||
},
|
||||
|
||||
showUser(username) {
|
||||
this.showUser(username);
|
||||
this._close();
|
||||
showUser(user) {
|
||||
this.handleShowUser(user);
|
||||
},
|
||||
|
||||
checkEmail(user) {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import Controller from "@ember/controller";
|
||||
import ModalFunctionality from "discourse/mixins/modal-functionality";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
import { action } from "@ember/object";
|
||||
import { next } from "@ember/runloop";
|
||||
import { userPath } from "discourse/lib/url";
|
||||
|
||||
|
@ -17,11 +18,13 @@ export default Controller.extend(ModalFunctionality, {
|
|||
});
|
||||
},
|
||||
|
||||
actions: {
|
||||
toggleExpanded() {
|
||||
this.set("expanded", !this.expanded);
|
||||
},
|
||||
@action
|
||||
toggleExpanded(event) {
|
||||
event?.preventDefault();
|
||||
this.set("expanded", !this.expanded);
|
||||
},
|
||||
|
||||
actions: {
|
||||
highlightSecure() {
|
||||
this.send("closeModal");
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import Controller from "@ember/controller";
|
||||
import { action } from "@ember/object";
|
||||
import ModalFunctionality from "discourse/mixins/modal-functionality";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
import { allowsImages } from "discourse/lib/uploads";
|
||||
|
@ -132,6 +133,15 @@ export default Controller.extend(ModalFunctionality, {
|
|||
);
|
||||
},
|
||||
|
||||
@action
|
||||
selectAvatar(url, event) {
|
||||
event?.preventDefault();
|
||||
this.user
|
||||
.selectAvatar(url)
|
||||
.then(() => window.location.reload())
|
||||
.catch(popupAjaxError);
|
||||
},
|
||||
|
||||
actions: {
|
||||
uploadComplete() {
|
||||
this.set("selected", "custom");
|
||||
|
@ -159,13 +169,6 @@ export default Controller.extend(ModalFunctionality, {
|
|||
.finally(() => this.set("gravatarRefreshDisabled", false));
|
||||
},
|
||||
|
||||
selectAvatar(url) {
|
||||
this.user
|
||||
.selectAvatar(url)
|
||||
.then(() => window.location.reload())
|
||||
.catch(popupAjaxError);
|
||||
},
|
||||
|
||||
saveAvatarSelection() {
|
||||
const selectedUploadId = this.selectedUploadId;
|
||||
const type = this.selected;
|
||||
|
|
|
@ -23,7 +23,7 @@ import { buildQuote } from "discourse/lib/quote";
|
|||
import deprecated from "discourse-common/lib/deprecated";
|
||||
import discourseDebounce from "discourse-common/lib/debounce";
|
||||
import { emojiUnescape } from "discourse/lib/text";
|
||||
import { escapeExpression } from "discourse/lib/utilities";
|
||||
import { escapeExpression, modKeysPressed } from "discourse/lib/utilities";
|
||||
import { getOwner } from "discourse-common/lib/get-owner";
|
||||
import getURL from "discourse-common/lib/get-url";
|
||||
import { isEmpty } from "@ember/utils";
|
||||
|
@ -508,11 +508,35 @@ export default Controller.extend({
|
|||
this.set("model.showFullScreenExitPrompt", false);
|
||||
},
|
||||
|
||||
actions: {
|
||||
togglePreview() {
|
||||
this.toggleProperty("showPreview");
|
||||
},
|
||||
@action
|
||||
async cancel(event) {
|
||||
event?.preventDefault();
|
||||
await this.cancelComposer();
|
||||
},
|
||||
|
||||
@action
|
||||
cancelUpload(event) {
|
||||
event?.preventDefault();
|
||||
this.set("model.uploadCancelled", true);
|
||||
},
|
||||
|
||||
@action
|
||||
togglePreview(event) {
|
||||
event?.preventDefault();
|
||||
this.toggleProperty("showPreview");
|
||||
},
|
||||
|
||||
@action
|
||||
viewNewReply(event) {
|
||||
if (event && modKeysPressed(event).length > 0) {
|
||||
return false;
|
||||
}
|
||||
event?.preventDefault();
|
||||
DiscourseURL.routeTo(this.get("model.createdPost.url"));
|
||||
this.close();
|
||||
},
|
||||
|
||||
actions: {
|
||||
closeComposer() {
|
||||
this.close();
|
||||
},
|
||||
|
@ -543,10 +567,6 @@ export default Controller.extend({
|
|||
});
|
||||
},
|
||||
|
||||
cancelUpload() {
|
||||
this.set("model.uploadCancelled", true);
|
||||
},
|
||||
|
||||
onPopupMenuAction(menuAction) {
|
||||
this.send(menuAction);
|
||||
},
|
||||
|
@ -707,10 +727,6 @@ export default Controller.extend({
|
|||
this.set("model.loading", false);
|
||||
},
|
||||
|
||||
async cancel() {
|
||||
await this.cancelComposer();
|
||||
},
|
||||
|
||||
save(ignore, event) {
|
||||
this.save(false, {
|
||||
jump:
|
||||
|
@ -1275,12 +1291,6 @@ export default Controller.extend({
|
|||
}
|
||||
},
|
||||
|
||||
viewNewReply() {
|
||||
DiscourseURL.routeTo(this.get("model.createdPost.url"));
|
||||
this.close();
|
||||
return false;
|
||||
},
|
||||
|
||||
async destroyDraft(draftSequence = null) {
|
||||
const key = this.get("model.draftKey");
|
||||
if (!key) {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import DiscoveryController from "discourse/controllers/discovery";
|
||||
import { inject as controller } from "@ember/controller";
|
||||
import { action } from "@ember/object";
|
||||
import { dasherize } from "@ember/string";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { reads } from "@ember/object/computed";
|
||||
|
@ -50,17 +51,19 @@ export default DiscoveryController.extend({
|
|||
: style;
|
||||
return dasherize(componentName);
|
||||
},
|
||||
|
||||
@action
|
||||
showInserted(event) {
|
||||
event?.preventDefault();
|
||||
const tracker = this.topicTrackingState;
|
||||
// Move inserted into topics
|
||||
this.model.loadBefore(tracker.get("newIncoming"), true);
|
||||
tracker.resetTracking();
|
||||
},
|
||||
|
||||
actions: {
|
||||
refresh() {
|
||||
this.send("triggerRefresh");
|
||||
},
|
||||
showInserted() {
|
||||
const tracker = this.topicTrackingState;
|
||||
|
||||
// Move inserted into topics
|
||||
this.model.loadBefore(tracker.get("newIncoming"), true);
|
||||
tracker.resetTracking();
|
||||
return false;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
|
@ -63,6 +63,17 @@ const controllerOpts = {
|
|||
return this._isFilterPage(filter, "new") && topicsLength > 0;
|
||||
},
|
||||
|
||||
// Show newly inserted topics
|
||||
@action
|
||||
showInserted(event) {
|
||||
event?.preventDefault();
|
||||
const tracker = this.topicTrackingState;
|
||||
|
||||
// Move inserted into topics
|
||||
this.model.loadBefore(tracker.get("newIncoming"), true);
|
||||
tracker.resetTracking();
|
||||
},
|
||||
|
||||
actions: {
|
||||
changeSort() {
|
||||
deprecated(
|
||||
|
@ -72,16 +83,6 @@ const controllerOpts = {
|
|||
return routeAction("changeSort", this.router._router, ...arguments)();
|
||||
},
|
||||
|
||||
// Show newly inserted topics
|
||||
showInserted() {
|
||||
const tracker = this.topicTrackingState;
|
||||
|
||||
// Move inserted into topics
|
||||
this.model.loadBefore(tracker.get("newIncoming"), true);
|
||||
tracker.resetTracking();
|
||||
return false;
|
||||
},
|
||||
|
||||
refresh(options = { skipResettingParams: [] }) {
|
||||
const filter = this.get("model.filter");
|
||||
this.send("resetParams", options.skipResettingParams);
|
||||
|
|
|
@ -14,6 +14,7 @@ import I18n from "I18n";
|
|||
import { ajax } from "discourse/lib/ajax";
|
||||
import { escapeExpression } from "discourse/lib/utilities";
|
||||
import { isEmpty } from "@ember/utils";
|
||||
import { action } from "@ember/object";
|
||||
import { gt, or } from "@ember/object/computed";
|
||||
import { scrollTop } from "discourse/mixins/scroll-top";
|
||||
import { setTransient } from "discourse/lib/page-tracker";
|
||||
|
@ -391,22 +392,24 @@ export default Controller.extend({
|
|||
}
|
||||
},
|
||||
|
||||
actions: {
|
||||
createTopic(searchTerm) {
|
||||
let topicCategory;
|
||||
if (searchTerm.includes("category:")) {
|
||||
const match = searchTerm.match(/category:(\S*)/);
|
||||
if (match && match[1]) {
|
||||
topicCategory = match[1];
|
||||
}
|
||||
@action
|
||||
createTopic(searchTerm, event) {
|
||||
event?.preventDefault();
|
||||
let topicCategory;
|
||||
if (searchTerm.includes("category:")) {
|
||||
const match = searchTerm.match(/category:(\S*)/);
|
||||
if (match && match[1]) {
|
||||
topicCategory = match[1];
|
||||
}
|
||||
this.composer.open({
|
||||
action: Composer.CREATE_TOPIC,
|
||||
draftKey: Composer.NEW_TOPIC_KEY,
|
||||
topicCategory,
|
||||
});
|
||||
},
|
||||
}
|
||||
this.composer.open({
|
||||
action: Composer.CREATE_TOPIC,
|
||||
draftKey: Composer.NEW_TOPIC_KEY,
|
||||
topicCategory,
|
||||
});
|
||||
},
|
||||
|
||||
actions: {
|
||||
selectAll() {
|
||||
this.selected.addObjects(this.get("model.posts").mapBy("topic"));
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { action } from "@ember/object";
|
||||
import { alias, equal, gt, not, or } from "@ember/object/computed";
|
||||
import discourseComputed, {
|
||||
observes,
|
||||
|
@ -313,6 +314,24 @@ export default Controller.extend(ModalFunctionality, {
|
|||
}
|
||||
},
|
||||
|
||||
@action
|
||||
displayInline(event) {
|
||||
event?.preventDefault();
|
||||
this.set("viewMode", "inline");
|
||||
},
|
||||
|
||||
@action
|
||||
displaySideBySide(event) {
|
||||
event?.preventDefault();
|
||||
this.set("viewMode", "side_by_side");
|
||||
},
|
||||
|
||||
@action
|
||||
displaySideBySideMarkdown(event) {
|
||||
event?.preventDefault();
|
||||
this.set("viewMode", "side_by_side_markdown");
|
||||
},
|
||||
|
||||
actions: {
|
||||
loadFirstVersion() {
|
||||
this.refresh(this.get("model.post_id"), this.get("model.first_revision"));
|
||||
|
@ -345,15 +364,5 @@ export default Controller.extend(ModalFunctionality, {
|
|||
revertToVersion() {
|
||||
this.revert(this.post, this.get("model.current_revision"));
|
||||
},
|
||||
|
||||
displayInline() {
|
||||
this.set("viewMode", "inline");
|
||||
},
|
||||
displaySideBySide() {
|
||||
this.set("viewMode", "side_by_side");
|
||||
},
|
||||
displaySideBySideMarkdown() {
|
||||
this.set("viewMode", "side_by_side_markdown");
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
|
@ -3,7 +3,7 @@ import { alias, not, or, readOnly } from "@ember/object/computed";
|
|||
import { areCookiesEnabled, escapeExpression } from "discourse/lib/utilities";
|
||||
import cookie, { removeCookie } from "discourse/lib/cookie";
|
||||
import { next, schedule } from "@ember/runloop";
|
||||
import EmberObject from "@ember/object";
|
||||
import EmberObject, { action } from "@ember/object";
|
||||
import I18n from "I18n";
|
||||
import ModalFunctionality from "discourse/mixins/modal-functionality";
|
||||
import { SECOND_FACTOR_METHODS } from "discourse/models/user";
|
||||
|
@ -133,7 +133,66 @@ export default Controller.extend(ModalFunctionality, {
|
|||
return canLoginLocalWithEmail;
|
||||
},
|
||||
|
||||
@action
|
||||
emailLogin(event) {
|
||||
event?.preventDefault();
|
||||
|
||||
if (this.processingEmailLink) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isEmpty(this.loginName)) {
|
||||
this.flash(I18n.t("login.blank_username"), "info");
|
||||
return;
|
||||
}
|
||||
|
||||
this.set("processingEmailLink", true);
|
||||
|
||||
ajax("/u/email-login", {
|
||||
data: { login: this.loginName.trim() },
|
||||
type: "POST",
|
||||
})
|
||||
.then((data) => {
|
||||
const loginName = escapeExpression(this.loginName);
|
||||
const isEmail = loginName.match(/@/);
|
||||
let key = `email_login.complete_${isEmail ? "email" : "username"}`;
|
||||
if (data.user_found === false) {
|
||||
this.flash(
|
||||
I18n.t(`${key}_not_found`, {
|
||||
email: loginName,
|
||||
username: loginName,
|
||||
}),
|
||||
"error"
|
||||
);
|
||||
} else {
|
||||
let postfix = data.hide_taken ? "" : "_found";
|
||||
this.flash(
|
||||
I18n.t(`${key}${postfix}`, {
|
||||
email: loginName,
|
||||
username: loginName,
|
||||
})
|
||||
);
|
||||
}
|
||||
})
|
||||
.catch((e) => this.flash(extractError(e), "error"))
|
||||
.finally(() => this.set("processingEmailLink", false));
|
||||
},
|
||||
|
||||
@action
|
||||
handleForgotPassword(event) {
|
||||
event?.preventDefault();
|
||||
const forgotPasswordController = this.forgotPassword;
|
||||
if (forgotPasswordController) {
|
||||
forgotPasswordController.set("accountEmailOrUsername", this.loginName);
|
||||
}
|
||||
this.send("showForgotPassword");
|
||||
},
|
||||
|
||||
actions: {
|
||||
forgotPassword() {
|
||||
this.handleForgotPassword();
|
||||
},
|
||||
|
||||
login() {
|
||||
if (this.loginDisabled) {
|
||||
return;
|
||||
|
@ -297,56 +356,6 @@ export default Controller.extend(ModalFunctionality, {
|
|||
this.send("showCreateAccount");
|
||||
},
|
||||
|
||||
forgotPassword() {
|
||||
const forgotPasswordController = this.forgotPassword;
|
||||
if (forgotPasswordController) {
|
||||
forgotPasswordController.set("accountEmailOrUsername", this.loginName);
|
||||
}
|
||||
this.send("showForgotPassword");
|
||||
},
|
||||
|
||||
emailLogin() {
|
||||
if (this.processingEmailLink) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isEmpty(this.loginName)) {
|
||||
this.flash(I18n.t("login.blank_username"), "info");
|
||||
return;
|
||||
}
|
||||
|
||||
this.set("processingEmailLink", true);
|
||||
|
||||
ajax("/u/email-login", {
|
||||
data: { login: this.loginName.trim() },
|
||||
type: "POST",
|
||||
})
|
||||
.then((data) => {
|
||||
const loginName = escapeExpression(this.loginName);
|
||||
const isEmail = loginName.match(/@/);
|
||||
let key = `email_login.complete_${isEmail ? "email" : "username"}`;
|
||||
if (data.user_found === false) {
|
||||
this.flash(
|
||||
I18n.t(`${key}_not_found`, {
|
||||
email: loginName,
|
||||
username: loginName,
|
||||
}),
|
||||
"error"
|
||||
);
|
||||
} else {
|
||||
let postfix = data.hide_taken ? "" : "_found";
|
||||
this.flash(
|
||||
I18n.t(`${key}${postfix}`, {
|
||||
email: loginName,
|
||||
username: loginName,
|
||||
})
|
||||
);
|
||||
}
|
||||
})
|
||||
.catch((e) => this.flash(extractError(e), "error"))
|
||||
.finally(() => this.set("processingEmailLink", false));
|
||||
},
|
||||
|
||||
authenticateSecurityKey() {
|
||||
getWebauthnCredential(
|
||||
this.securityKeyChallenge,
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import DiscourseURL, { userPath } from "discourse/lib/url";
|
||||
import { action } from "@ember/object";
|
||||
import { alias, or, readOnly } from "@ember/object/computed";
|
||||
import Controller from "@ember/controller";
|
||||
import I18n from "I18n";
|
||||
|
@ -8,6 +9,7 @@ import { ajax } from "discourse/lib/ajax";
|
|||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import getURL from "discourse-common/lib/get-url";
|
||||
import { getWebauthnCredential } from "discourse/lib/webauthn";
|
||||
import { modKeysPressed } from "discourse/lib/utilities";
|
||||
|
||||
export default Controller.extend(PasswordValidation, {
|
||||
isDeveloper: alias("model.is_developer"),
|
||||
|
@ -46,6 +48,16 @@ export default Controller.extend(PasswordValidation, {
|
|||
|
||||
lockImageUrl: getURL("/images/lock.svg"),
|
||||
|
||||
@action
|
||||
done(event) {
|
||||
if (event && modKeysPressed(event).length > 0) {
|
||||
return false;
|
||||
}
|
||||
event?.preventDefault();
|
||||
this.set("redirected", true);
|
||||
DiscourseURL.redirectTo(this.redirectTo || "/");
|
||||
},
|
||||
|
||||
actions: {
|
||||
submit() {
|
||||
ajax({
|
||||
|
@ -126,10 +138,5 @@ export default Controller.extend(PasswordValidation, {
|
|||
}
|
||||
);
|
||||
},
|
||||
|
||||
done() {
|
||||
this.set("redirected", true);
|
||||
DiscourseURL.redirectTo(this.redirectTo || "/");
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
|
@ -2,7 +2,7 @@ import { gt, not, or } from "@ember/object/computed";
|
|||
import { propertyNotEqual, setting } from "discourse/lib/computed";
|
||||
import CanCheckEmails from "discourse/mixins/can-check-emails";
|
||||
import Controller from "@ember/controller";
|
||||
import EmberObject from "@ember/object";
|
||||
import EmberObject, { action } from "@ember/object";
|
||||
import I18n from "I18n";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { findAll } from "discourse/models/login-method";
|
||||
|
@ -132,6 +132,20 @@ export default Controller.extend(CanCheckEmails, {
|
|||
return findAll().length > 0;
|
||||
},
|
||||
|
||||
@action
|
||||
resendConfirmationEmail(email, event) {
|
||||
event?.preventDefault();
|
||||
email.set("resending", true);
|
||||
this.model
|
||||
.addEmail(email.email)
|
||||
.then(() => {
|
||||
email.set("resent", true);
|
||||
})
|
||||
.finally(() => {
|
||||
email.set("resending", false);
|
||||
});
|
||||
},
|
||||
|
||||
actions: {
|
||||
save() {
|
||||
this.set("saved", false);
|
||||
|
@ -157,18 +171,6 @@ export default Controller.extend(CanCheckEmails, {
|
|||
this.model.destroyEmail(email);
|
||||
},
|
||||
|
||||
resendConfirmationEmail(email) {
|
||||
email.set("resending", true);
|
||||
this.model
|
||||
.addEmail(email.email)
|
||||
.then(() => {
|
||||
email.set("resent", true);
|
||||
})
|
||||
.finally(() => {
|
||||
email.set("resending", false);
|
||||
});
|
||||
},
|
||||
|
||||
delete() {
|
||||
this.dialog.alert({
|
||||
message: I18n.t("user.delete_account_confirm"),
|
||||
|
|
|
@ -3,6 +3,7 @@ import CanCheckEmails from "discourse/mixins/can-check-emails";
|
|||
import Controller from "@ember/controller";
|
||||
import I18n from "I18n";
|
||||
import { SECOND_FACTOR_METHODS } from "discourse/models/user";
|
||||
import { action } from "@ember/object";
|
||||
import { alias } from "@ember/object/computed";
|
||||
import bootbox from "bootbox";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
|
@ -91,6 +92,27 @@ export default Controller.extend(CanCheckEmails, {
|
|||
this.set("dirty", true);
|
||||
},
|
||||
|
||||
@action
|
||||
resetPassword(event) {
|
||||
event?.preventDefault();
|
||||
|
||||
this.setProperties({
|
||||
resetPasswordLoading: true,
|
||||
resetPasswordProgress: "",
|
||||
});
|
||||
|
||||
return this.model
|
||||
.changePassword()
|
||||
.then(() => {
|
||||
this.set(
|
||||
"resetPasswordProgress",
|
||||
I18n.t("user.change_password.success")
|
||||
);
|
||||
})
|
||||
.catch(popupAjaxError)
|
||||
.finally(() => this.set("resetPasswordLoading", false));
|
||||
},
|
||||
|
||||
actions: {
|
||||
confirmPassword() {
|
||||
if (!this.password) {
|
||||
|
@ -101,24 +123,6 @@ export default Controller.extend(CanCheckEmails, {
|
|||
this.set("password", null);
|
||||
},
|
||||
|
||||
resetPassword() {
|
||||
this.setProperties({
|
||||
resetPasswordLoading: true,
|
||||
resetPasswordProgress: "",
|
||||
});
|
||||
|
||||
return this.model
|
||||
.changePassword()
|
||||
.then(() => {
|
||||
this.set(
|
||||
"resetPasswordProgress",
|
||||
I18n.t("user.change_password.success")
|
||||
);
|
||||
})
|
||||
.catch(popupAjaxError)
|
||||
.finally(() => this.set("resetPasswordLoading", false));
|
||||
},
|
||||
|
||||
disableAllSecondFactors() {
|
||||
if (this.loading) {
|
||||
return;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import Controller from "@ember/controller";
|
||||
import { action } from "@ember/object";
|
||||
import { gt } from "@ember/object/computed";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
|
@ -51,6 +52,56 @@ export default Controller.extend(CanCheckEmails, {
|
|||
DEFAULT_AUTH_TOKENS_COUNT
|
||||
),
|
||||
|
||||
@action
|
||||
changePassword(event) {
|
||||
event?.preventDefault();
|
||||
if (!this.passwordProgress) {
|
||||
this.set("passwordProgress", I18n.t("user.change_password.in_progress"));
|
||||
return this.model
|
||||
.changePassword()
|
||||
.then(() => {
|
||||
// password changed
|
||||
this.setProperties({
|
||||
changePasswordProgress: false,
|
||||
passwordProgress: I18n.t("user.change_password.success"),
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
// password failed to change
|
||||
this.setProperties({
|
||||
changePasswordProgress: false,
|
||||
passwordProgress: I18n.t("user.change_password.error"),
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
@action
|
||||
toggleShowAllAuthTokens(event) {
|
||||
event?.preventDefault();
|
||||
this.toggleProperty("showAllAuthTokens");
|
||||
},
|
||||
|
||||
@action
|
||||
revokeAuthToken(token, event) {
|
||||
event?.preventDefault();
|
||||
ajax(
|
||||
userPath(
|
||||
`${this.get("model.username_lower")}/preferences/revoke-auth-token`
|
||||
),
|
||||
{
|
||||
type: "POST",
|
||||
data: token ? { token_id: token.id } : {},
|
||||
}
|
||||
)
|
||||
.then(() => {
|
||||
if (!token) {
|
||||
logout();
|
||||
} // All sessions revoked
|
||||
})
|
||||
.catch(popupAjaxError);
|
||||
},
|
||||
|
||||
actions: {
|
||||
save() {
|
||||
this.set("saved", false);
|
||||
|
@ -60,53 +111,6 @@ export default Controller.extend(CanCheckEmails, {
|
|||
.catch(popupAjaxError);
|
||||
},
|
||||
|
||||
changePassword() {
|
||||
if (!this.passwordProgress) {
|
||||
this.set(
|
||||
"passwordProgress",
|
||||
I18n.t("user.change_password.in_progress")
|
||||
);
|
||||
return this.model
|
||||
.changePassword()
|
||||
.then(() => {
|
||||
// password changed
|
||||
this.setProperties({
|
||||
changePasswordProgress: false,
|
||||
passwordProgress: I18n.t("user.change_password.success"),
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
// password failed to change
|
||||
this.setProperties({
|
||||
changePasswordProgress: false,
|
||||
passwordProgress: I18n.t("user.change_password.error"),
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
toggleShowAllAuthTokens() {
|
||||
this.toggleProperty("showAllAuthTokens");
|
||||
},
|
||||
|
||||
revokeAuthToken(token) {
|
||||
ajax(
|
||||
userPath(
|
||||
`${this.get("model.username_lower")}/preferences/revoke-auth-token`
|
||||
),
|
||||
{
|
||||
type: "POST",
|
||||
data: token ? { token_id: token.id } : {},
|
||||
}
|
||||
)
|
||||
.then(() => {
|
||||
if (!token) {
|
||||
logout();
|
||||
} // All sessions revoked
|
||||
})
|
||||
.catch(popupAjaxError);
|
||||
},
|
||||
|
||||
showToken(token) {
|
||||
showModal("auth-token", { model: token });
|
||||
},
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import Controller from "@ember/controller";
|
||||
import { action } from "@ember/object";
|
||||
import I18n from "I18n";
|
||||
import ModalFunctionality from "discourse/mixins/modal-functionality";
|
||||
|
||||
|
@ -40,9 +41,15 @@ export default Controller.extend(ModalFunctionality, {
|
|||
.finally(() => this.set("loading", false));
|
||||
},
|
||||
|
||||
@action
|
||||
enableShowSecondFactorKey(event) {
|
||||
event?.preventDefault();
|
||||
this.set("showSecondFactorKey", true);
|
||||
},
|
||||
|
||||
actions: {
|
||||
showSecondFactorKey() {
|
||||
this.set("showSecondFactorKey", true);
|
||||
this.enableShowSecondFactorKey();
|
||||
},
|
||||
|
||||
enableSecondFactor() {
|
||||
|
|
|
@ -212,7 +212,8 @@ export default Controller.extend({
|
|||
},
|
||||
|
||||
@action
|
||||
useAnotherMethod(newMethod) {
|
||||
useAnotherMethod(newMethod, event) {
|
||||
event?.preventDefault();
|
||||
this.set("userSelectedMethod", newMethod);
|
||||
},
|
||||
|
||||
|
|
|
@ -110,7 +110,8 @@ export default DiscoverySortableController.extend(
|
|||
},
|
||||
|
||||
@action
|
||||
showInserted() {
|
||||
showInserted(event) {
|
||||
event?.preventDefault();
|
||||
const tracker = this.topicTrackingState;
|
||||
this.list.loadBefore(tracker.newIncoming, true);
|
||||
tracker.resetTracking();
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { action } from "@ember/object";
|
||||
import { alias, notEmpty } from "@ember/object/computed";
|
||||
import Controller from "@ember/controller";
|
||||
import I18n from "I18n";
|
||||
|
@ -41,23 +42,27 @@ export default Controller.extend({
|
|||
};
|
||||
},
|
||||
|
||||
@action
|
||||
sortByCount(event) {
|
||||
event?.preventDefault();
|
||||
this.setProperties({
|
||||
sortProperties: ["totalCount:desc", "id"],
|
||||
sortedByCount: true,
|
||||
sortedByName: false,
|
||||
});
|
||||
},
|
||||
|
||||
@action
|
||||
sortById(event) {
|
||||
event?.preventDefault();
|
||||
this.setProperties({
|
||||
sortProperties: ["id"],
|
||||
sortedByCount: false,
|
||||
sortedByName: true,
|
||||
});
|
||||
},
|
||||
|
||||
actions: {
|
||||
sortByCount() {
|
||||
this.setProperties({
|
||||
sortProperties: ["totalCount:desc", "id"],
|
||||
sortedByCount: true,
|
||||
sortedByName: false,
|
||||
});
|
||||
},
|
||||
|
||||
sortById() {
|
||||
this.setProperties({
|
||||
sortProperties: ["id"],
|
||||
sortedByCount: false,
|
||||
sortedByName: true,
|
||||
});
|
||||
},
|
||||
|
||||
showUploader() {
|
||||
showModal("tag-upload");
|
||||
},
|
||||
|
|
|
@ -19,7 +19,7 @@ import { ajax } from "discourse/lib/ajax";
|
|||
import { bufferedProperty } from "discourse/mixins/buffered-content";
|
||||
import { buildQuote } from "discourse/lib/quote";
|
||||
import { deepMerge } from "discourse-common/lib/object";
|
||||
import { escapeExpression } from "discourse/lib/utilities";
|
||||
import { escapeExpression, modKeysPressed } from "discourse/lib/utilities";
|
||||
import { extractLinkMeta } from "discourse/lib/render-topic-featured-link";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
import { inject as service } from "@ember/service";
|
||||
|
@ -313,6 +313,58 @@ export default Controller.extend(bufferedProperty("model"), {
|
|||
});
|
||||
},
|
||||
|
||||
@action
|
||||
editTopic(event) {
|
||||
event?.preventDefault();
|
||||
if (this.get("model.details.can_edit")) {
|
||||
this.set("editingTopic", true);
|
||||
}
|
||||
},
|
||||
|
||||
@action
|
||||
jumpTop(event) {
|
||||
if (event && modKeysPressed(event).length > 0) {
|
||||
return false;
|
||||
}
|
||||
event?.preventDefault();
|
||||
DiscourseURL.routeTo(this.get("model.firstPostUrl"), {
|
||||
skipIfOnScreen: false,
|
||||
keepFilter: true,
|
||||
});
|
||||
},
|
||||
|
||||
@action
|
||||
removeFeaturedLink(event) {
|
||||
event?.preventDefault();
|
||||
this.set("buffered.featured_link", null);
|
||||
},
|
||||
|
||||
@action
|
||||
selectAll(event) {
|
||||
event?.preventDefault();
|
||||
const smallActionsPostIds = this._smallActionPostIds();
|
||||
this.set("selectedPostIds", [
|
||||
...this.get("model.postStream.stream").filter(
|
||||
(postId) => !smallActionsPostIds.has(postId)
|
||||
),
|
||||
]);
|
||||
this._forceRefreshPostStream();
|
||||
},
|
||||
|
||||
@action
|
||||
deselectAll(event) {
|
||||
event?.preventDefault();
|
||||
this.set("selectedPostIds", []);
|
||||
this._forceRefreshPostStream();
|
||||
},
|
||||
|
||||
@action
|
||||
toggleMultiSelect(event) {
|
||||
event?.preventDefault();
|
||||
this.toggleProperty("multiSelect");
|
||||
this._forceRefreshPostStream();
|
||||
},
|
||||
|
||||
actions: {
|
||||
topicCategoryChanged(categoryId) {
|
||||
this.set("buffered.category_id", categoryId);
|
||||
|
@ -822,13 +874,6 @@ export default Controller.extend(bufferedProperty("model"), {
|
|||
this._jumpToPostNumber(postNumber);
|
||||
},
|
||||
|
||||
jumpTop() {
|
||||
DiscourseURL.routeTo(this.get("model.firstPostUrl"), {
|
||||
skipIfOnScreen: false,
|
||||
keepFilter: true,
|
||||
});
|
||||
},
|
||||
|
||||
jumpBottom() {
|
||||
// When a topic only has one lengthy post
|
||||
const jumpEnd = this.model.highest_post_number === 1 ? true : false;
|
||||
|
@ -859,26 +904,6 @@ export default Controller.extend(bufferedProperty("model"), {
|
|||
this._jumpToPostId(postId);
|
||||
},
|
||||
|
||||
toggleMultiSelect() {
|
||||
this.toggleProperty("multiSelect");
|
||||
this._forceRefreshPostStream();
|
||||
},
|
||||
|
||||
selectAll() {
|
||||
const smallActionsPostIds = this._smallActionPostIds();
|
||||
this.set("selectedPostIds", [
|
||||
...this.get("model.postStream.stream").filter(
|
||||
(postId) => !smallActionsPostIds.has(postId)
|
||||
),
|
||||
]);
|
||||
this._forceRefreshPostStream();
|
||||
},
|
||||
|
||||
deselectAll() {
|
||||
this.set("selectedPostIds", []);
|
||||
this._forceRefreshPostStream();
|
||||
},
|
||||
|
||||
togglePostSelection(post) {
|
||||
const selected = this.selectedPostIds;
|
||||
selected.includes(post.id)
|
||||
|
@ -973,13 +998,6 @@ export default Controller.extend(bufferedProperty("model"), {
|
|||
.then(() => this.updateQueryParams);
|
||||
},
|
||||
|
||||
editTopic() {
|
||||
if (this.get("model.details.can_edit")) {
|
||||
this.set("editingTopic", true);
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
cancelEditingTopic() {
|
||||
this.set("editingTopic", false);
|
||||
this.rollbackBuffer();
|
||||
|
@ -1159,10 +1177,6 @@ export default Controller.extend(bufferedProperty("model"), {
|
|||
.catch(popupAjaxError);
|
||||
},
|
||||
|
||||
removeFeaturedLink() {
|
||||
this.set("buffered.featured_link", null);
|
||||
},
|
||||
|
||||
resetBumpDate() {
|
||||
this.model.resetBumpDate();
|
||||
},
|
||||
|
|
|
@ -1,25 +1,29 @@
|
|||
import Controller from "@ember/controller";
|
||||
import { action } from "@ember/object";
|
||||
|
||||
export default Controller.extend({
|
||||
sortProperties: ["count:desc", "id"],
|
||||
tagsForUser: null,
|
||||
sortedByCount: true,
|
||||
sortedByName: false,
|
||||
|
||||
actions: {
|
||||
sortByCount() {
|
||||
this.setProperties({
|
||||
sortProperties: ["count:desc", "id"],
|
||||
sortedByCount: true,
|
||||
sortedByName: false,
|
||||
});
|
||||
},
|
||||
@action
|
||||
sortByCount(event) {
|
||||
event?.preventDefault();
|
||||
this.setProperties({
|
||||
sortProperties: ["count:desc", "id"],
|
||||
sortedByCount: true,
|
||||
sortedByName: false,
|
||||
});
|
||||
},
|
||||
|
||||
sortById() {
|
||||
this.setProperties({
|
||||
sortProperties: ["id"],
|
||||
sortedByCount: false,
|
||||
sortedByName: true,
|
||||
});
|
||||
},
|
||||
@action
|
||||
sortById(event) {
|
||||
event?.preventDefault();
|
||||
this.setProperties({
|
||||
sortProperties: ["id"],
|
||||
sortedByCount: false,
|
||||
sortedByName: true,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
|
|
@ -81,10 +81,10 @@ export default Controller.extend(BulkTopicSelection, {
|
|||
},
|
||||
|
||||
@action
|
||||
showInserted() {
|
||||
showInserted(event) {
|
||||
event?.preventDefault();
|
||||
this.model.loadBefore(this.pmTopicTrackingState.newIncoming);
|
||||
this.pmTopicTrackingState.resetIncomingTracking();
|
||||
return false;
|
||||
},
|
||||
|
||||
@action
|
||||
|
|
|
@ -211,6 +211,15 @@ export default Controller.extend(CanCheckEmails, {
|
|||
}
|
||||
},
|
||||
|
||||
@action
|
||||
showSuspensions(event) {
|
||||
event?.preventDefault();
|
||||
this.adminTools.showActionLogs(this, {
|
||||
target_user: this.get("model.username"),
|
||||
action_name: "suspend_user",
|
||||
});
|
||||
},
|
||||
|
||||
actions: {
|
||||
collapseProfile() {
|
||||
this.set("forceExpand", false);
|
||||
|
@ -220,13 +229,6 @@ export default Controller.extend(CanCheckEmails, {
|
|||
this.set("forceExpand", true);
|
||||
},
|
||||
|
||||
showSuspensions() {
|
||||
this.adminTools.showActionLogs(this, {
|
||||
target_user: this.get("model.username"),
|
||||
action_name: "suspend_user",
|
||||
});
|
||||
},
|
||||
|
||||
adminDelete() {
|
||||
const userId = this.get("model.id");
|
||||
const location = document.location.pathname;
|
||||
|
|
|
@ -489,6 +489,12 @@ export function inCodeBlock(text, pos) {
|
|||
return lastOpenBlock !== -1 && pos >= end + lastOpenBlock;
|
||||
}
|
||||
|
||||
// Return an array of modifier keys that are pressed during a given `MouseEvent`
|
||||
// or `KeyboardEvent`.
|
||||
export function modKeysPressed(event) {
|
||||
return ["alt", "shift", "meta", "ctrl"].filter((key) => event[`${key}Key`]);
|
||||
}
|
||||
|
||||
export function translateModKey(string) {
|
||||
const { isApple } = helperContext().capabilities;
|
||||
// Apple device users are used to glyphs for shortcut keys
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
|
||||
{{#if this.mutedCategories}}
|
||||
<div class="muted-categories">
|
||||
<a href class="muted-categories-link" {{action "toggleShowMuted"}}>
|
||||
<a href class="muted-categories-link" {{on "click" this.toggleShowMuted}}>
|
||||
<h3 class="muted-categories-heading">{{i18n "categories.muted"}}</h3>
|
||||
{{#if this.mutedToggleIcon}}
|
||||
{{d-icon this.mutedToggleIcon}}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<span class="group-name">
|
||||
<span class="group-name-label">{{this.group_name}}</span>
|
||||
<a class="remove-permission" href {{action "removeRow"}}>
|
||||
<a class="remove-permission" href {{on "click" this.removeRow}}>
|
||||
{{d-icon "far-trash-alt"}}
|
||||
</a>
|
||||
</span>
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
{{#each this.messages as |m|}}
|
||||
<div class="controls existing-message">
|
||||
<label class="radio">
|
||||
<input id="choose-message-{{m.id}}" {{action "chooseMessage" m}} type="radio" name="choose_message_id">
|
||||
<input id="choose-message-{{m.id}}" {{on "click" (fn this.chooseMessage m)}} type="radio" name="choose_message_id">
|
||||
<span class="message-title">
|
||||
{{m.title}}
|
||||
</span>
|
||||
|
|
|
@ -1 +1 @@
|
|||
<a href {{action "select"}} class={{if this.active "active"}}>{{this.title}}</a>
|
||||
<a href {{on "click" this.select}} class={{if this.active "active"}}>{{this.title}}</a>
|
||||
|
|
|
@ -1,30 +1,30 @@
|
|||
{{!-- DO NOT EDIT THIS FILE!!! --}}
|
||||
{{!-- Update it by running `rake javascript:update_constants` --}}
|
||||
|
||||
<button type="button" data-section="smileys_&_emotion" {{action this.onCategorySelection "smileys_&_emotion"}} class="btn btn-default category-button emoji">
|
||||
<button type="button" data-section="smileys_&_emotion" {{on "click" (fn this.onCategorySelection "smileys_&_emotion")}} class="btn btn-default category-button emoji">
|
||||
{{replace-emoji ":grinning:"}}
|
||||
</button>
|
||||
<button type="button" data-section="people_&_body" {{action this.onCategorySelection "people_&_body"}} class="btn btn-default category-button emoji">
|
||||
<button type="button" data-section="people_&_body" {{on "click" (fn this.onCategorySelection "people_&_body")}} class="btn btn-default category-button emoji">
|
||||
{{replace-emoji ":wave:"}}
|
||||
</button>
|
||||
<button type="button" data-section="animals_&_nature" {{action this.onCategorySelection "animals_&_nature"}} class="btn btn-default category-button emoji">
|
||||
<button type="button" data-section="animals_&_nature" {{on "click" (fn this.onCategorySelection "animals_&_nature")}} class="btn btn-default category-button emoji">
|
||||
{{replace-emoji ":evergreen_tree:"}}
|
||||
</button>
|
||||
<button type="button" data-section="food_&_drink" {{action this.onCategorySelection "food_&_drink"}} class="btn btn-default category-button emoji">
|
||||
<button type="button" data-section="food_&_drink" {{on "click" (fn this.onCategorySelection "food_&_drink")}} class="btn btn-default category-button emoji">
|
||||
{{replace-emoji ":hamburger:"}}
|
||||
</button>
|
||||
<button type="button" data-section="travel_&_places" {{action this.onCategorySelection "travel_&_places"}} class="btn btn-default category-button emoji">
|
||||
<button type="button" data-section="travel_&_places" {{on "click" (fn this.onCategorySelection "travel_&_places")}} class="btn btn-default category-button emoji">
|
||||
{{replace-emoji ":airplane:"}}
|
||||
</button>
|
||||
<button type="button" data-section="activities" {{action this.onCategorySelection "activities"}} class="btn btn-default category-button emoji">
|
||||
<button type="button" data-section="activities" {{on "click" (fn this.onCategorySelection "activities")}} class="btn btn-default category-button emoji">
|
||||
{{replace-emoji ":soccer:"}}
|
||||
</button>
|
||||
<button type="button" data-section="objects" {{action this.onCategorySelection "objects"}} class="btn btn-default category-button emoji">
|
||||
<button type="button" data-section="objects" {{on "click" (fn this.onCategorySelection "objects")}} class="btn btn-default category-button emoji">
|
||||
{{replace-emoji ":eyeglasses:"}}
|
||||
</button>
|
||||
<button type="button" data-section="symbols" {{action this.onCategorySelection "symbols"}} class="btn btn-default category-button emoji">
|
||||
<button type="button" data-section="symbols" {{on "click" (fn this.onCategorySelection "symbols")}} class="btn btn-default category-button emoji">
|
||||
{{replace-emoji ":white_check_mark:"}}
|
||||
</button>
|
||||
<button type="button" data-section="flags" {{action this.onCategorySelection "flags"}} class="btn btn-default category-button emoji">
|
||||
<button type="button" data-section="flags" {{on "click" (fn this.onCategorySelection "flags")}} class="btn btn-default category-button emoji">
|
||||
{{replace-emoji ":checkered_flag:"}}
|
||||
</button>
|
||||
|
|
|
@ -4,15 +4,15 @@
|
|||
{{!-- template-lint-enable no-invalid-interactive no-down-event-binding --}}
|
||||
<div class="emoji-picker-category-buttons">
|
||||
{{#if this.recentEmojis.length}}
|
||||
<button type="button" data-section="recent" {{action "onCategorySelection" "recent"}} class="btn btn-default category-button emoji">
|
||||
<button type="button" data-section="recent" {{on "click" (fn this.onCategorySelection "recent")}} class="btn btn-default category-button emoji">
|
||||
{{replace-emoji ":star:"}}
|
||||
</button>
|
||||
{{/if}}
|
||||
|
||||
<EmojiGroupButtons @onCategorySelection={{action "onCategorySelection"}} @tagName="" />
|
||||
<EmojiGroupButtons @onCategorySelection={{this.onCategorySelection}} @tagName="" />
|
||||
|
||||
{{#each-in this.customEmojis as |group emojis|}}
|
||||
<button type="button" data-section={{concat "custom-" group}} {{action "onCategorySelection" (concat "custom-" group)}} class="btn btn-default category-button emoji">
|
||||
<button type="button" data-section={{concat "custom-" group}} {{on "click" (fn this.onCategorySelection (concat "custom-" group))}} class="btn btn-default category-button emoji">
|
||||
{{replace-emoji (concat ":" emojis.firstObject.code ":")}}
|
||||
</button>
|
||||
{{/each-in}}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<h3>{{this.formattedName}}</h3>
|
||||
<div class="controls">
|
||||
<label class="radio">
|
||||
<input id="radio_{{this.flag.name_key}}" {{action "changePostActionType" this.flag}} type="radio" name="post_action_type_index">
|
||||
<input id="radio_{{this.flag.name_key}}" {{on "click" (action "changePostActionType" this.flag)}} type="radio" name="post_action_type_index">
|
||||
|
||||
<div class="flag-action-type-details">
|
||||
<span class="description">{{html-safe this.flag.description}}</span>
|
||||
|
@ -19,7 +19,7 @@
|
|||
{{else}}
|
||||
<div class="controls {{this.flag.name_key}}">
|
||||
<label class="radio">
|
||||
<input id="radio_{{this.flag.name_key}}" {{action "changePostActionType" this.flag}} type="radio" name="post_action_type_index">
|
||||
<input id="radio_{{this.flag.name_key}}" {{on "click" (action "changePostActionType" this.flag)}} type="radio" name="post_action_type_index">
|
||||
<div class="flag-action-type-details">
|
||||
<strong>{{this.formattedName}}</strong>
|
||||
{{#if this.showDescription}}
|
||||
|
|
|
@ -13,14 +13,14 @@
|
|||
{{else}}
|
||||
<div class="card-row first-row">
|
||||
<div class="group-card-avatar">
|
||||
<a href={{this.groupPath}} {{action "showGroup" this.group}} class="card-huge-avatar">
|
||||
<a href={{this.groupPath}} {{on "click" (fn this.handleShowGroup this.group)}} class="card-huge-avatar">
|
||||
<AvatarFlair @flairName={{this.group.name}} @flairUrl={{this.group.flair_url}} @flairBgColor={{this.group.flair_bg_color}} @flairColor={{this.group.flair_color}} />
|
||||
</a>
|
||||
</div>
|
||||
<div class="names">
|
||||
<span>
|
||||
<h1 class={{this.group.name}}>
|
||||
<a href={{this.groupPath}} {{action "showGroup" this.group}} class="group-page-link">{{this.group.name}}</a>
|
||||
<a href={{this.groupPath}} {{on "click" (fn this.handleShowGroup this.group)}} class="group-page-link">{{this.group.name}}</a>
|
||||
</h1>
|
||||
{{#if this.group.full_name}}
|
||||
<h2 class="full-name">{{this.group.full_name}}</h2>
|
||||
|
@ -53,10 +53,10 @@
|
|||
<div class="card-row third-row">
|
||||
<div class="members metadata">
|
||||
{{#each this.group.members as |user|}}
|
||||
<a {{action "close"}} href={{user.path}} class="card-tiny-avatar">{{bound-avatar user "tiny"}}</a>
|
||||
<a {{on "click" this.close}} href={{user.path}} class="card-tiny-avatar">{{bound-avatar user "tiny"}}</a>
|
||||
{{/each}}
|
||||
{{#if this.showMoreMembers}}
|
||||
<a href={{this.groupPath}} {{action "showGroup" this.group}} class="more-members-link">
|
||||
<a href={{this.groupPath}} {{on "click" (fn this.handleShowGroup this.group)}} class="more-members-link">
|
||||
<span class="more-members-count">+{{this.moreMembersCount}} {{i18n "more"}}</span>
|
||||
</a>
|
||||
{{/if}}
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
|
||||
<div class="control-group">
|
||||
<div class="group-imap-prefill-options">
|
||||
{{i18n "groups.manage.email.prefill.title"}} <a id="prefill_imap_gmail" href {{action "prefillSettings" "gmail"}}>{{i18n "groups.manage.email.prefill.gmail"}}</a>
|
||||
{{i18n "groups.manage.email.prefill.title"}} <a id="prefill_imap_gmail" href {{on "click" (fn this.prefillSettings "gmail")}}>{{i18n "groups.manage.email.prefill.gmail"}}</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<p>{{i18n "groups.manage.email.smtp_instructions"}}</p>
|
||||
|
||||
<label for="enable_smtp">
|
||||
<Input @type="checkbox" @checked={{this.group.smtp_enabled}} id="enable_smtp" tabindex="1" {{on "change" (action "smtpEnabledChange")}} />
|
||||
<Input @type="checkbox" @checked={{this.group.smtp_enabled}} id="enable_smtp" tabindex="1" {{on "change" this.smtpEnabledChange}} />
|
||||
{{i18n "groups.manage.email.enable_smtp"}}
|
||||
</label>
|
||||
|
||||
|
@ -23,7 +23,7 @@
|
|||
<div class="alert alert-warning">{{i18n "groups.manage.email.imap_alpha_warning"}}</div>
|
||||
|
||||
<label for="enable_imap">
|
||||
<Input @type="checkbox" disabled={{not this.enableImapSettings}} @checked={{this.group.imap_enabled}} id="enable_imap" tabindex="8" {{on "change" (action "imapEnabledChange")}} />
|
||||
<Input @type="checkbox" disabled={{not this.enableImapSettings}} @checked={{this.group.imap_enabled}} id="enable_imap" tabindex="8" {{on "change" this.imapEnabledChange}} />
|
||||
{{i18n "groups.manage.email.enable_imap"}}
|
||||
</label>
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
</a>
|
||||
<span>{{this.member.username}}</span>
|
||||
{{#unless this.automatic}}
|
||||
<a href {{action "remove"}} class="remove">
|
||||
<a href {{on "click" this.remove}} class="remove">
|
||||
{{d-icon "times"}}
|
||||
</a>
|
||||
{{/unless}}
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
|
||||
<div class="control-group">
|
||||
<div class="group-smtp-prefill-options">
|
||||
{{i18n "groups.manage.email.prefill.title"}} <a id="prefill_smtp_gmail" href {{action "prefillSettings" "gmail"}}>{{i18n "groups.manage.email.prefill.gmail"}}</a>
|
||||
{{i18n "groups.manage.email.prefill.title"}} <a id="prefill_smtp_gmail" href {{on "click" (fn this.prefillSettings "gmail")}}>{{i18n "groups.manage.email.prefill.gmail"}}</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{{#each this.buttons as |b|}}
|
||||
<button type="button" class="btn btn-social {{b.name}}" {{action this.externalLogin b}} aria-label={{b.screenReaderTitle}} tabindex="3">
|
||||
<button type="button" class="btn btn-social {{b.name}}" {{on "click" (action this.externalLogin b)}} aria-label={{b.screenReaderTitle}} tabindex="3">
|
||||
{{#if b.isGoogle}}
|
||||
<svg class="fa d-icon d-icon-custom-google-oauth2 svg-icon" viewBox="0 0 48 48"><defs><path id="a" d="M44.5 20H24v8.5h11.8C34.7 33.9 30.1 37 24 37c-7.2 0-13-5.8-13-13s5.8-13 13-13c3.1 0 5.9 1.1 8.1 2.9l6.4-6.4C34.6 4.1 29.6 2 24 2 11.8 2 2 11.8 2 24s9.8 22 22 22c11 0 21-8 21-22 0-1.3-.2-2.7-.5-4z"/></defs><clipPath id="b"><use href="#a" overflow="visible"/></clipPath><path clip-path="url(#b)" fill="#FBBC05" d="M0 37V11l17 13z"/><path clip-path="url(#b)" fill="#EA4335" d="M0 11l17 13 7-6.1L48 14V0H0z"/><path clip-path="url(#b)" fill="#34A853" d="M0 37l30-23 7.9 1L48 0v48H0z"/><path clip-path="url(#b)" fill="#4285F4" d="M48 48L17 24l-4-3 35-10z"/></svg>
|
||||
{{else if b.icon}}
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
<span class="status">
|
||||
{{reviewable-status this.reviewable.status}}
|
||||
</span>
|
||||
<a href {{action "explainReviewable" this.reviewable}} title={{i18n "review.explain.why"}} class="explain">
|
||||
<a href {{on "click" (fn this.explainReviewable this.reviewable)}} title={{i18n "review.explain.why"}} class="explain">
|
||||
{{d-icon "question-circle"}}
|
||||
</a>
|
||||
</div>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{{#if this.hasEdits}}
|
||||
<a href {{action "showEditHistory"}} class="has-edits {{this.historyClass}}" title={{i18n "post.last_edited_on" dateTime=this.editedDate}}>
|
||||
<a href {{on "click" this.showEditHistory}} class="has-edits {{this.historyClass}}" title={{i18n "post.last_edited_on" dateTime=this.editedDate}}>
|
||||
{{d-icon "pencil-alt"}}
|
||||
</a>
|
||||
{{/if}}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
{{category-badge this.reviewable.category}}
|
||||
<ReviewableTags @tags={{this.reviewable.payload.tags}} @tagName="" />
|
||||
{{#if this.reviewable.payload.via_email}}
|
||||
<a href {{action "showRawEmail"}} class="show-raw-email">
|
||||
<a href {{on "click" this.showRawEmail}} class="show-raw-email">
|
||||
{{d-icon "far-envelope" title="post.via_email"}}
|
||||
</a>
|
||||
{{/if}}
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
<TrackSelected @selectedList={{this.selected}} @selectedId={{this.post.topic}} @class="bulk-select" />
|
||||
{{/if}}
|
||||
|
||||
<a href={{this.post.url}} {{action "logClick" this.post.topic_id}} class="search-link{{if this.post.topic.visited " visited"}}" role="heading" aria-level="2">
|
||||
<a href={{this.post.url}} {{on "click" (fn this.logClick this.post.topic_id)}} class="search-link{{if this.post.topic.visited " visited"}}" role="heading" aria-level="2">
|
||||
{{raw "topic-status" topic=this.post.topic showPrivateMessageIcon=true}}
|
||||
<span class="topic-title">
|
||||
{{#if this.post.useTopicTitleHeadline}}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
{{yield}}
|
||||
{{#if this.showToggleMethodLink}}
|
||||
<p>
|
||||
<a href="" class="toggle-second-factor-method" {{action "toggleSecondFactorMethod"}}>{{ i18n this.linkText }}</a>
|
||||
<a href class="toggle-second-factor-method" {{on "click" this.toggleSecondFactorMethod}}>{{ i18n this.linkText }}</a>
|
||||
</p>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<DButton @action={{this.action}} @icon="key" @id="security-key-authenticate-button" @label="login.security_key_authenticate" @type="button" @class="btn btn-large btn-primary" />
|
||||
<p>
|
||||
{{#if this.otherMethodAllowed}}
|
||||
<a href="" class="toggle-second-factor-method" {{action "useAnotherMethod"}}>{{ i18n "login.security_key_alternative" }}</a>
|
||||
<a href class="toggle-second-factor-method" {{on "click" this.useAnotherMethod}}>{{ i18n "login.security_key_alternative" }}</a>
|
||||
{{/if}}
|
||||
</p>
|
||||
</div>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
{{#if this.canSelectAll}}
|
||||
<p>
|
||||
<a class="select-all" href {{action this.selectAll}}>
|
||||
<a class="select-all" href {{on "click" this.selectAll}}>
|
||||
{{i18n "topic.multi_select.select_all"}}
|
||||
</a>
|
||||
</p>
|
||||
|
@ -12,7 +12,7 @@
|
|||
|
||||
{{#if this.canDeselectAll}}
|
||||
<p>
|
||||
<a href {{action this.deselectAll}}>
|
||||
<a href {{on "click" this.deselectAll}}>
|
||||
{{i18n "topic.multi_select.deselect_all"}}
|
||||
</a>
|
||||
</p>
|
||||
|
@ -35,7 +35,7 @@
|
|||
{{/if}}
|
||||
|
||||
<p class="cancel">
|
||||
<a href {{action this.toggleMultiSelect}}>
|
||||
<a href {{on "click" this.toggleMultiSelect}}>
|
||||
{{i18n "topic.multi_select.cancel"}}
|
||||
</a>
|
||||
</p>
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
<div class="buttons">
|
||||
<DButton @action={{route-action "showCreateAccount"}} @label="signup_cta.sign_up" @icon="user" @class="btn-primary" />
|
||||
<DButton @action={{action "hideForSession"}} @label="signup_cta.hide_session" @class="no-icon" />
|
||||
<a href {{action "neverShow"}}>{{i18n "signup_cta.hide_forever"}}</a>
|
||||
<a href {{on "click" this.neverShow}}>{{i18n "signup_cta.hide_forever"}}</a>
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
<div class="tag-name-wrapper">
|
||||
{{discourse-tag this.tagInfo.name tagName="div"}}
|
||||
{{#if this.canAdminTag}}
|
||||
<a href {{action "edit"}} class="edit-tag" title={{i18n "tagging.edit_tag"}}>{{d-icon "pencil-alt"}}</a>
|
||||
<a href {{on "click" this.edit}} class="edit-tag" title={{i18n "tagging.edit_tag"}}>{{d-icon "pencil-alt"}}</a>
|
||||
{{/if}}
|
||||
</div>
|
||||
<div class="tag-description-wrapper">
|
||||
|
@ -56,10 +56,10 @@
|
|||
<div class="tag-box">
|
||||
{{discourse-tag tag.id pmOnly=tag.pmOnly tagName="div"}}
|
||||
{{#if this.editSynonymsMode}}
|
||||
<a href {{action "unlinkSynonym" tag}} class="unlink-synonym">
|
||||
<a href {{on "click" (fn this.unlinkSynonym tag)}} class="unlink-synonym">
|
||||
{{d-icon "unlink" title="tagging.remove_synonym"}}
|
||||
</a>
|
||||
<a href {{action "deleteSynonym" tag}} class="delete-synonym">
|
||||
<a href {{on "click" (fn this.deleteSynonym tag)}} class="delete-synonym">
|
||||
{{d-icon "far-trash-alt" title="tagging.delete_tag"}}
|
||||
</a>
|
||||
{{/if}}
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
{{#if this.user.profile_hidden}}
|
||||
<span class="card-huge-avatar">{{bound-avatar this.user "huge"}}</span>
|
||||
{{else}}
|
||||
<a href={{this.user.path}} {{action "showUser" this.user}} class="card-huge-avatar">{{bound-avatar this.user "huge"}}</a>
|
||||
<a href={{this.user.path}} {{on "click" (fn this.handleShowUser this.user)}} class="card-huge-avatar">{{bound-avatar this.user "huge"}}</a>
|
||||
{{/if}}
|
||||
|
||||
<UserAvatarFlair @user={{this.user}} />
|
||||
|
@ -40,7 +40,7 @@
|
|||
{{if this.nameFirst this.user.name (format-username this.user.username)}}
|
||||
</span>
|
||||
{{else}}
|
||||
<a href={{this.user.path}} {{action "showUser" this.user}} class="user-profile-link">
|
||||
<a href={{this.user.path}} {{on "click" (fn this.handleShowUser this.user)}} class="user-profile-link">
|
||||
<span id="discourse-user-card-title" class="name-username-wrapper">
|
||||
{{if this.nameFirst this.user.name (format-username this.user.username)}}
|
||||
</span>
|
||||
|
@ -48,7 +48,7 @@
|
|||
</a>
|
||||
{{/if}}
|
||||
</h1>
|
||||
<PluginOutlet @name="user-card-after-username" @connectorTagName="div" @args={{hash user=this.user showUser=(action "showUser" this.user)}} />
|
||||
<PluginOutlet @name="user-card-after-username" @connectorTagName="div" @args={{hash user=this.user showUser=(fn this.handleShowUser this.user)}} />
|
||||
{{#if this.nameFirst}}
|
||||
<h2 class="username">{{this.user.username}}</h2>
|
||||
{{else}}
|
||||
|
|
|
@ -101,7 +101,7 @@
|
|||
<ComposerSaveButton @action={{action "save"}} @icon={{this.saveIcon}} @label={{this.saveLabel}} @forwardEvent={{true}} @disableSubmit={{this.disableSubmit}} />
|
||||
|
||||
{{#if this.site.mobileView}}
|
||||
<a href {{action "cancel"}} title={{i18n "cancel"}} class="cancel">
|
||||
<a href {{on "click" this.cancel}} title={{i18n "cancel"}} class="cancel">
|
||||
{{#if this.canEdit}}
|
||||
{{d-icon "times"}}
|
||||
{{else}}
|
||||
|
@ -109,7 +109,7 @@
|
|||
{{/if}}
|
||||
</a>
|
||||
{{else}}
|
||||
<a href {{action "cancel"}} class="cancel" >{{i18n "close"}}</a>
|
||||
<a href {{on "click" this.cancel}} class="cancel" >{{i18n "close"}}</a>
|
||||
{{/if}}
|
||||
|
||||
{{#if this.site.mobileView}}
|
||||
|
@ -133,7 +133,7 @@
|
|||
{{/if}}
|
||||
|
||||
{{#if this.isCancellable}}
|
||||
<a href id="cancel-file-upload" {{action "cancelUpload"}}>{{d-icon "times"}}</a>
|
||||
<a href id="cancel-file-upload" {{on "click" this.cancelUpload}}>{{d-icon "times"}}</a>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
||||
|
@ -165,7 +165,7 @@
|
|||
</a>
|
||||
{{/if}}
|
||||
|
||||
<a href class="btn btn-default no-text mobile-preview" title={{i18n "composer.show_preview"}} {{action "togglePreview"}} aria-label={{i18n "preview"}}>
|
||||
<a href class="btn btn-default no-text mobile-preview" title={{i18n "composer.show_preview"}} {{on "click" this.togglePreview}} aria-label={{i18n "preview"}}>
|
||||
{{d-icon "desktop"}}
|
||||
</a>
|
||||
|
||||
|
@ -180,7 +180,7 @@
|
|||
{{else}}
|
||||
<div class="saving-text">
|
||||
{{#if this.model.createdPost}}
|
||||
{{i18n "composer.saved"}} <a href={{this.createdPost.url}} {{action "viewNewReply"}} class="permalink">{{i18n "composer.view_new_post"}}</a>
|
||||
{{i18n "composer.saved"}} <a href={{this.createdPost.url}} {{on "click" this.viewNewReply}} class="permalink">{{i18n "composer.view_new_post"}}</a>
|
||||
{{else}}
|
||||
{{i18n "composer.saving"}} {{loading-spinner size="small"}}
|
||||
{{/if}}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<a href {{action this.closeMessage this.message}} class="close" aria-label={{i18n "composer.esc_label"}}>
|
||||
<a href {{on "click" (fn this.closeMessage this.message)}} class="close" aria-label={{i18n "composer.esc_label"}}>
|
||||
{{i18n "composer.esc"}} {{d-icon "times"}}
|
||||
</a>
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<a href {{action this.closeMessage this.message}} class="close" aria-label={{i18n "composer.esc_label"}}>
|
||||
<a href {{on "click" (fn this.closeMessage this.message)}} class="close" aria-label={{i18n "composer.esc_label"}}>
|
||||
{{i18n "composer.esc"}} {{d-icon "times"}}
|
||||
</a>
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<a href {{action this.closeMessage this.message}} class="close" aria-label={{i18n "composer.esc_label"}}>
|
||||
<a href {{on "click" (fn this.closeMessage this.message)}} class="close" aria-label={{i18n "composer.esc_label"}}>
|
||||
{{i18n "composer.esc"}} {{d-icon "times"}}
|
||||
</a>
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<a href {{action this.closeMessage this.message}} class="close" aria-label={{i18n "composer.esc_label"}}>
|
||||
<a href {{on "click" (fn this.closeMessage this.message)}} class="close" aria-label={{i18n "composer.esc_label"}}>
|
||||
{{i18n "composer.esc"}} {{d-icon "times"}}
|
||||
</a>
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<a href {{action this.closeMessage this.message}} class="close" aria-label={{i18n "composer.esc_label"}}>
|
||||
<a href {{on "click" (fn this.closeMessage this.message)}} class="close" aria-label={{i18n "composer.esc_label"}}>
|
||||
{{i18n "composer.esc"}} {{d-icon "times"}}
|
||||
</a>
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<DiscoveryCategories @refresh={{action "refresh"}}>
|
||||
{{#if (and this.topicTrackingState.hasIncoming this.isCategoriesRoute)}}
|
||||
<div class="show-more {{if this.hasTopics "has-topics"}}">
|
||||
<div role="button" class="alert alert-info clickable" {{action "showInserted"}}>
|
||||
<div role="button" class="alert alert-info clickable" {{on "click" this.showInserted}}>
|
||||
<CountI18n @key="topic_count_" @suffix={{this.topicTrackingState.filter}} @count={{this.topicTrackingState.incomingCount}} />
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
{{else}}
|
||||
{{#if this.topicTrackingState.hasIncoming}}
|
||||
<div class="show-more {{if this.hasTopics "has-topics"}}">
|
||||
<a tabindex="0" href {{action "showInserted"}} class="alert alert-info clickable">
|
||||
<a tabindex="0" href {{on "click" this.showInserted}} class="alert alert-info clickable">
|
||||
<CountI18n @key="topic_count_" @suffix={{this.topicTrackingState.filter}} @count={{this.topicTrackingState.incomingCount}} />
|
||||
</a>
|
||||
</div>
|
||||
|
|
|
@ -101,7 +101,7 @@
|
|||
<div class="no-results-suggestion">
|
||||
{{i18n "search.cant_find"}}
|
||||
{{#if this.canCreateTopic}}
|
||||
<a href {{action "createTopic" this.searchTerm}}>{{i18n "search.start_new_topic"}}</a>
|
||||
<a href {{on "click" (fn this.createTopic this.searchTerm)}}>{{i18n "search.start_new_topic"}}</a>
|
||||
{{#unless this.siteSettings.login_required}}
|
||||
{{i18n "search.or_search_google"}}
|
||||
{{/unless}}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue