DEV: implements <DropdownMenu /> (#26917)
DropdownMenu component is meant as a way to describe the content of menus. Syntax: ``` <DropdownMenu as |dm|> <dm.item class="test"> First </dm.item> <dm.divider class="foo" /> <dm.item class="bar"> Second </dm.item> </DropdownMenu> ```
This commit is contained in:
parent
21bce2d07e
commit
cf8b81771f
|
@ -4,6 +4,7 @@ import { action } from "@ember/object";
|
|||
import { service } from "@ember/service";
|
||||
import { and, not, or } from "truth-helpers";
|
||||
import DButton from "discourse/components/d-button";
|
||||
import DropdownMenu from "discourse/components/dropdown-menu";
|
||||
import concatClass from "discourse/helpers/concat-class";
|
||||
|
||||
export default class AdminPostMenu extends Component {
|
||||
|
@ -46,20 +47,20 @@ export default class AdminPostMenu extends Component {
|
|||
}
|
||||
|
||||
<template>
|
||||
<ul>
|
||||
<DropdownMenu as |dropdown|>
|
||||
{{#if this.currentUser.staff}}
|
||||
<li>
|
||||
<dropdown.item>
|
||||
<DButton
|
||||
@label="review.moderation_history"
|
||||
@icon="list"
|
||||
class="btn btn-transparent moderation-history"
|
||||
@href={{this.reviewUrl}}
|
||||
/>
|
||||
</li>
|
||||
</dropdown.item>
|
||||
{{/if}}
|
||||
|
||||
{{#if (and this.currentUser.staff (not @data.transformedPost.isWhisper))}}
|
||||
<li>
|
||||
<dropdown.item>
|
||||
<DButton
|
||||
@label={{if
|
||||
@data.transformedPost.isModeratorAction
|
||||
|
@ -73,11 +74,11 @@ export default class AdminPostMenu extends Component {
|
|||
}}
|
||||
@action={{fn this.topicAction "togglePostType"}}
|
||||
/>
|
||||
</li>
|
||||
</dropdown.item>
|
||||
{{/if}}
|
||||
|
||||
{{#if @data.transformedPost.canEditStaffNotes}}
|
||||
<li>
|
||||
<dropdown.item>
|
||||
<DButton
|
||||
@icon="user-shield"
|
||||
@label={{if
|
||||
|
@ -93,18 +94,18 @@ export default class AdminPostMenu extends Component {
|
|||
}}
|
||||
@action={{fn this.topicAction "changeNotice"}}
|
||||
/>
|
||||
</li>
|
||||
</dropdown.item>
|
||||
{{/if}}
|
||||
|
||||
{{#if (and this.currentUser.staff @data.transformedPost.hidden)}}
|
||||
<li>
|
||||
<dropdown.item>
|
||||
<DButton
|
||||
@label="post.controls.unhide"
|
||||
@icon="far-eye"
|
||||
class="btn btn-transparent unhide-post"
|
||||
@action={{fn this.topicAction "unhidePost"}}
|
||||
/>
|
||||
</li>
|
||||
</dropdown.item>
|
||||
{{/if}}
|
||||
|
||||
{{#if
|
||||
|
@ -116,7 +117,7 @@ export default class AdminPostMenu extends Component {
|
|||
)
|
||||
)
|
||||
}}
|
||||
<li>
|
||||
<dropdown.item>
|
||||
<DButton
|
||||
@label="post.controls.change_owner"
|
||||
@icon="user"
|
||||
|
@ -124,23 +125,23 @@ export default class AdminPostMenu extends Component {
|
|||
class="btn btn-transparent change-owner"
|
||||
@action={{fn this.topicAction "changePostOwner"}}
|
||||
/>
|
||||
</li>
|
||||
</dropdown.item>
|
||||
{{/if}}
|
||||
|
||||
{{#if (and @data.transformedPost.user_id this.currentUser.staff)}}
|
||||
{{#if this.siteSettings.enable_badges}}
|
||||
<li>
|
||||
<dropdown.item>
|
||||
<DButton
|
||||
@label="post.controls.grant_badge"
|
||||
@icon="certificate"
|
||||
class="btn btn-transparent grant-badge"
|
||||
@action={{fn this.topicAction "grantBadge"}}
|
||||
/>
|
||||
</li>
|
||||
</dropdown.item>
|
||||
{{/if}}
|
||||
|
||||
{{#if @data.transformedPost.locked}}
|
||||
<li>
|
||||
<dropdown.item>
|
||||
<DButton
|
||||
@label="post.controls.unlock_post"
|
||||
@icon="unlock"
|
||||
|
@ -151,9 +152,9 @@ export default class AdminPostMenu extends Component {
|
|||
}}
|
||||
@action={{fn this.topicAction "unlockPost"}}
|
||||
/>
|
||||
</li>
|
||||
</dropdown.item>
|
||||
{{else}}
|
||||
<li>
|
||||
<dropdown.item>
|
||||
<DButton
|
||||
@label="post.controls.lock_post"
|
||||
@icon="lock"
|
||||
|
@ -161,24 +162,24 @@ export default class AdminPostMenu extends Component {
|
|||
class="btn btn-transparent lock-post"
|
||||
@action={{fn this.topicAction "lockPost"}}
|
||||
/>
|
||||
</li>
|
||||
</dropdown.item>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
|
||||
{{#if @data.transformedPost.canPermanentlyDelete}}
|
||||
<li>
|
||||
<dropdown.item>
|
||||
<DButton
|
||||
@label="post.controls.permanently_delete"
|
||||
@icon="trash-alt"
|
||||
class="btn btn-transparent permanently-delete"
|
||||
@action={{fn this.topicAction "permanentlyDeletePost"}}
|
||||
/>
|
||||
</li>
|
||||
</dropdown.item>
|
||||
{{/if}}
|
||||
|
||||
{{#if (or @data.transformedPost.canManage @data.transformedPost.canWiki)}}
|
||||
{{#if @data.transformedPost.wiki}}
|
||||
<li>
|
||||
<dropdown.item>
|
||||
<DButton
|
||||
@label="post.controls.unwiki"
|
||||
@icon="far-edit"
|
||||
|
@ -188,43 +189,43 @@ export default class AdminPostMenu extends Component {
|
|||
}}
|
||||
@action={{fn this.topicAction "toggleWiki"}}
|
||||
/>
|
||||
</li>
|
||||
</dropdown.item>
|
||||
{{else}}
|
||||
<li>
|
||||
<dropdown.item>
|
||||
<DButton
|
||||
@label="post.controls.wiki"
|
||||
@icon="far-edit"
|
||||
class="btn btn-transparent wiki"
|
||||
@action={{fn this.topicAction "toggleWiki"}}
|
||||
/>
|
||||
</li>
|
||||
</dropdown.item>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
|
||||
{{#if @data.transformedPost.canPublishPage}}
|
||||
<li>
|
||||
<dropdown.item>
|
||||
<DButton
|
||||
@label="post.controls.publish_page"
|
||||
@icon="file"
|
||||
class="btn btn-transparent publish-page"
|
||||
@action={{fn this.topicAction "showPagePublish"}}
|
||||
/>
|
||||
</li>
|
||||
</dropdown.item>
|
||||
{{/if}}
|
||||
|
||||
{{#if @data.transformedPost.canManage}}
|
||||
<li>
|
||||
<dropdown.item>
|
||||
<DButton
|
||||
@label="post.controls.rebake"
|
||||
@icon="sync-alt"
|
||||
class="btn btn-transparent rebuild-html"
|
||||
@action={{fn this.topicAction "rebakePost"}}
|
||||
/>
|
||||
</li>
|
||||
</dropdown.item>
|
||||
{{/if}}
|
||||
|
||||
{{#each this.extraButtons as |button|}}
|
||||
<li>
|
||||
<dropdown.item>
|
||||
<DButton
|
||||
@label={{button.label}}
|
||||
@translatedLabel={{button.translatedLabel}}
|
||||
|
@ -232,8 +233,8 @@ export default class AdminPostMenu extends Component {
|
|||
class={{concatClass "btn btn-transparent" button.className}}
|
||||
@action={{fn this.extraAction button}}
|
||||
/>
|
||||
</li>
|
||||
</dropdown.item>
|
||||
{{/each}}
|
||||
</ul>
|
||||
</DropdownMenu>
|
||||
</template>
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import { action } from "@ember/object";
|
|||
import didInsert from "@ember/render-modifiers/modifiers/did-insert";
|
||||
import { inject as service } from "@ember/service";
|
||||
import DButton from "discourse/components/d-button";
|
||||
import DropdownMenu from "discourse/components/dropdown-menu";
|
||||
import BookmarkModal from "discourse/components/modal/bookmark";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
import {
|
||||
|
@ -249,65 +250,69 @@ export default class BookmarkMenu extends Component {
|
|||
@arrow={{false}}
|
||||
>
|
||||
<:content>
|
||||
<div class="bookmark-menu__body">
|
||||
|
||||
<DropdownMenu as |dropdown|>
|
||||
{{#unless this.showEditDeleteMenu}}
|
||||
<div class="bookmark-menu__title">{{icon "check-circle"}}<span
|
||||
>{{i18n "bookmarks.bookmarked_success"}}</span>
|
||||
</div>
|
||||
<dropdown.item class="bookmark-menu__title">
|
||||
{{icon "check-circle"}}
|
||||
<span>{{i18n "bookmarks.bookmarked_success"}}</span>
|
||||
</dropdown.item>
|
||||
{{/unless}}
|
||||
|
||||
{{#if this.showEditDeleteMenu}}
|
||||
{{#if this.site.mobileView}}
|
||||
<div class="bookmark-menu__title">{{icon "bookmark"}}<span>{{i18n
|
||||
"bookmarks.bookmark"
|
||||
}}</span>
|
||||
</div>
|
||||
<dropdown.item class="bookmark-menu__title">
|
||||
{{icon "bookmark"}}
|
||||
<span>{{i18n "bookmarks.bookmark"}}</span>
|
||||
</dropdown.item>
|
||||
{{/if}}
|
||||
<ul class="bookmark-menu__actions">
|
||||
<li class="bookmark-menu__row -edit" data-menu-option-id="edit">
|
||||
<DButton
|
||||
@icon="pencil-alt"
|
||||
@label="edit"
|
||||
@action={{this.onEditBookmark}}
|
||||
@class="bookmark-menu__row-btn btn-transparent"
|
||||
/>
|
||||
</li>
|
||||
<li
|
||||
class="bookmark-menu__row --remove"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
data-menu-option-id="delete"
|
||||
|
||||
<dropdown.item
|
||||
class="bookmark-menu__row -edit"
|
||||
data-menu-option-id="edit"
|
||||
>
|
||||
<DButton
|
||||
@icon="pencil-alt"
|
||||
@label="edit"
|
||||
@action={{this.onEditBookmark}}
|
||||
@class="bookmark-menu__row-btn btn-transparent"
|
||||
/>
|
||||
</dropdown.item>
|
||||
<dropdown.item
|
||||
class="bookmark-menu__row --remove"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
data-menu-option-id="delete"
|
||||
>
|
||||
<DButton
|
||||
@icon="trash-alt"
|
||||
@label="delete"
|
||||
@action={{this.onRemoveBookmark}}
|
||||
@class="bookmark-menu__row-btn btn-transparent btn-danger"
|
||||
/>
|
||||
</dropdown.item>
|
||||
|
||||
{{else}}
|
||||
<dropdown.item class="bookmark-menu__row-title">
|
||||
{{i18n "bookmarks.also_set_reminder"}}
|
||||
</dropdown.item>
|
||||
|
||||
<dropdown.divider />
|
||||
|
||||
{{#each this.reminderAtOptions as |option|}}
|
||||
<dropdown.item
|
||||
class="bookmark-menu__row"
|
||||
data-menu-option-id={{option.id}}
|
||||
>
|
||||
<DButton
|
||||
@icon="trash-alt"
|
||||
@label="delete"
|
||||
@action={{this.onRemoveBookmark}}
|
||||
@class="bookmark-menu__row-btn btn-transparent btn-danger"
|
||||
@label={{option.label}}
|
||||
@translatedTitle={{this.reminderShortcutTimeTitle option}}
|
||||
@action={{fn this.onChooseReminderOption option}}
|
||||
@class="bookmark-menu__row-btn btn-transparent"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
{{else}}
|
||||
<span class="bookmark-menu__row-title">{{i18n
|
||||
"bookmarks.also_set_reminder"
|
||||
}}</span>
|
||||
<ul class="bookmark-menu__actions">
|
||||
{{#each this.reminderAtOptions as |option|}}
|
||||
<li
|
||||
class="bookmark-menu__row"
|
||||
data-menu-option-id={{option.id}}
|
||||
>
|
||||
<DButton
|
||||
@label={{option.label}}
|
||||
@translatedTitle={{this.reminderShortcutTimeTitle option}}
|
||||
@action={{fn this.onChooseReminderOption option}}
|
||||
@class="bookmark-menu__row-btn btn-transparent"
|
||||
/>
|
||||
</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
</dropdown.item>
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
</div>
|
||||
</DropdownMenu>
|
||||
</:content>
|
||||
</DMenu>
|
||||
</template>
|
||||
|
|
|
@ -1,22 +1,29 @@
|
|||
import Component from "@glimmer/component";
|
||||
import { fn } from "@ember/helper";
|
||||
import { action } from "@ember/object";
|
||||
import { service } from "@ember/service";
|
||||
import DButton from "discourse/components/d-button";
|
||||
import DropdownMenu from "discourse/components/dropdown-menu";
|
||||
import BulkTopicActions, {
|
||||
addBulkDropdownAction,
|
||||
} from "discourse/components/modal/bulk-topic-actions";
|
||||
import concatClass from "discourse/helpers/concat-class";
|
||||
import icon from "discourse-common/helpers/d-icon";
|
||||
import i18n from "discourse-common/helpers/i18n";
|
||||
import DropdownSelectBoxComponent from "select-kit/components/dropdown-select-box";
|
||||
import DMenu from "float-kit/components/d-menu";
|
||||
|
||||
const _customButtons = [];
|
||||
const _customOnSelection = {};
|
||||
|
||||
export function addBulkDropdownButton(opts) {
|
||||
_customButtons.push({
|
||||
id: opts.label,
|
||||
id: opts.id,
|
||||
icon: opts.icon,
|
||||
name: i18n(opts.label),
|
||||
visible: opts.visible,
|
||||
class: opts.class,
|
||||
});
|
||||
addBulkDropdownAction(opts.label, opts.action);
|
||||
addBulkDropdownAction(opts.id, opts.action);
|
||||
const actionOpts = {
|
||||
label: opts.label,
|
||||
setComponent: true,
|
||||
|
@ -24,27 +31,17 @@ export function addBulkDropdownButton(opts) {
|
|||
if (opts.actionType === "performAndRefresh") {
|
||||
actionOpts.setComponent = false;
|
||||
}
|
||||
_customOnSelection[opts.label] = actionOpts;
|
||||
_customOnSelection[opts.id] = actionOpts;
|
||||
}
|
||||
|
||||
export default DropdownSelectBoxComponent.extend({
|
||||
classNames: ["bulk-select-topics-dropdown"],
|
||||
headerIcon: null,
|
||||
showFullTitle: true,
|
||||
selectKitOptions: {
|
||||
showCaret: true,
|
||||
showFullTitle: true,
|
||||
none: "select_kit.components.bulk_select_topics_dropdown.title",
|
||||
},
|
||||
export default class BulkSelectTopicsDropdown extends Component {
|
||||
@service modal;
|
||||
@service router;
|
||||
@service currentUser;
|
||||
@service siteSettings;
|
||||
|
||||
modal: service(),
|
||||
router: service(),
|
||||
currentUser: service(),
|
||||
siteSettings: service(),
|
||||
|
||||
computeContent() {
|
||||
let options = [];
|
||||
options = options.concat([
|
||||
get buttons() {
|
||||
let options = [
|
||||
{
|
||||
id: "update-category",
|
||||
icon: "pencil-alt",
|
||||
|
@ -119,12 +116,12 @@ export default DropdownSelectBoxComponent.extend({
|
|||
name: i18n("topic_bulk_actions.delete_topics.name"),
|
||||
visible: ({ currentUser }) => currentUser.staff,
|
||||
},
|
||||
]);
|
||||
];
|
||||
|
||||
return [...options, ..._customButtons].filter(({ visible }) => {
|
||||
if (visible) {
|
||||
return visible({
|
||||
topics: this.bulkSelectHelper.selected,
|
||||
topics: this.args.bulkSelectHelper.selected,
|
||||
currentUser: this.currentUser,
|
||||
siteSettings: this.siteSettings,
|
||||
});
|
||||
|
@ -132,7 +129,7 @@ export default DropdownSelectBoxComponent.extend({
|
|||
return true;
|
||||
}
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
showBulkTopicActionsModal(actionName, title, opts = {}) {
|
||||
let allowSilent = false;
|
||||
|
@ -160,14 +157,14 @@ export default DropdownSelectBoxComponent.extend({
|
|||
action: actionName,
|
||||
title,
|
||||
description,
|
||||
bulkSelectHelper: this.bulkSelectHelper,
|
||||
bulkSelectHelper: this.args.bulkSelectHelper,
|
||||
refreshClosure: () => this.router.refresh(),
|
||||
allowSilent,
|
||||
initialAction,
|
||||
initialActionLabel,
|
||||
},
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
@action
|
||||
onSelect(id) {
|
||||
|
@ -228,5 +225,43 @@ export default DropdownSelectBoxComponent.extend({
|
|||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
this.dMenu.close();
|
||||
}
|
||||
|
||||
@action
|
||||
onRegisterApi(api) {
|
||||
this.dMenu = api;
|
||||
}
|
||||
|
||||
<template>
|
||||
<DMenu
|
||||
@modalForMobile={{true}}
|
||||
@autofocus={{true}}
|
||||
@identifier="bulk-select-topics-dropdown"
|
||||
@onRegisterApi={{this.onRegisterApi}}
|
||||
>
|
||||
<:trigger>
|
||||
<span class="d-button-label">
|
||||
{{i18n "select_kit.components.bulk_select_topics_dropdown.title"}}
|
||||
</span>
|
||||
{{icon "angle-down"}}
|
||||
</:trigger>
|
||||
|
||||
<:content>
|
||||
<DropdownMenu as |dropdown|>
|
||||
{{#each this.buttons as |button|}}
|
||||
<dropdown.item>
|
||||
<DButton
|
||||
@translatedLabel={{button.name}}
|
||||
@icon={{button.icon}}
|
||||
class={{concatClass "btn-transparent" button.id button.class}}
|
||||
@action={{fn this.onSelect button.id}}
|
||||
/>
|
||||
</dropdown.item>
|
||||
{{/each}}
|
||||
</DropdownMenu>
|
||||
</:content>
|
||||
</DMenu>
|
||||
</template>
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
import { hash } from "@ember/helper";
|
||||
|
||||
const DropdownItem = <template>
|
||||
<li class="dropdown-menu__item" ...attributes>{{yield}}</li>
|
||||
</template>;
|
||||
|
||||
const DropdownDivider = <template>
|
||||
<li ...attributes><hr class="dropdown-menu__divider" /></li>
|
||||
</template>;
|
||||
|
||||
const DropdownMenu = <template>
|
||||
<ul class="dropdown-menu" ...attributes>
|
||||
{{yield (hash item=DropdownItem divider=DropdownDivider)}}
|
||||
</ul>
|
||||
</template>;
|
||||
|
||||
export default DropdownMenu;
|
|
@ -4,6 +4,7 @@ import { action } from "@ember/object";
|
|||
import { inject as service } from "@ember/service";
|
||||
import { and, not, or } from "truth-helpers";
|
||||
import DButton from "discourse/components/d-button";
|
||||
import DropdownMenu from "discourse/components/dropdown-menu";
|
||||
import concatClass from "discourse/helpers/concat-class";
|
||||
import icon from "discourse-common/helpers/d-icon";
|
||||
import getURL from "discourse-common/lib/get-url";
|
||||
|
@ -85,249 +86,230 @@ export default class TopicAdminMenu extends Component {
|
|||
<span class="topic-admin-menu-button-container">
|
||||
<span class="topic-admin-menu-button">
|
||||
<DMenu
|
||||
@identifier="topic-admin-menu"
|
||||
@onRegisterApi={{this.onRegisterApi}}
|
||||
@triggerClass="toggle-admin-menu"
|
||||
@modalForMobile={{true}}
|
||||
@autofocus={{true}}
|
||||
>
|
||||
<:trigger>
|
||||
{{icon "wrench"}}
|
||||
</:trigger>
|
||||
<:content>
|
||||
<div class="popup-menu topic-admin-popup-menu">
|
||||
<ul>
|
||||
<ul class="topic-admin-menu-topic">
|
||||
{{#if
|
||||
(or
|
||||
this.currentUser.canManageTopic
|
||||
this.details.can_split_merge_topic
|
||||
)
|
||||
}}
|
||||
<li class="topic-admin-multi-select">
|
||||
<DButton
|
||||
class="btn-transparent"
|
||||
@label="topic.actions.multi_select"
|
||||
@action={{fn this.onButtonAction "toggleMultiSelect"}}
|
||||
@icon="tasks"
|
||||
/>
|
||||
</li>
|
||||
{{/if}}
|
||||
<DropdownMenu as |dropdown|>
|
||||
{{#if
|
||||
(or
|
||||
this.currentUser.canManageTopic
|
||||
this.details.can_split_merge_topic
|
||||
)
|
||||
}}
|
||||
<dropdown.item class="topic-admin-multi-select">
|
||||
<DButton
|
||||
class="btn-transparent"
|
||||
@label="topic.actions.multi_select"
|
||||
@action={{fn this.onButtonAction "toggleMultiSelect"}}
|
||||
@icon="tasks"
|
||||
/>
|
||||
</dropdown.item>
|
||||
{{/if}}
|
||||
|
||||
{{#if
|
||||
(or
|
||||
this.currentUser.canManageTopic
|
||||
this.details.can_moderate_category
|
||||
)
|
||||
}}
|
||||
{{#if this.canDelete}}
|
||||
<li class="topic-admin-delete">
|
||||
<DButton
|
||||
@label="topic.actions.delete"
|
||||
@action={{fn this.onButtonAction "deleteTopic"}}
|
||||
@icon="far-trash-alt"
|
||||
class="popup-menu-btn-danger btn-danger btn-transparent"
|
||||
/>
|
||||
</li>
|
||||
{{else if this.canRecover}}
|
||||
<li class="topic-admin-recover">
|
||||
<DButton
|
||||
class="btn-transparent"
|
||||
@label="topic.actions.recover"
|
||||
@action={{fn this.onButtonAction "recoverTopic"}}
|
||||
@icon="undo"
|
||||
/>
|
||||
</li>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
|
||||
{{#if this.details.can_close_topic}}
|
||||
<li
|
||||
class={{if
|
||||
@topic.closed
|
||||
"topic-admin-open"
|
||||
"topic-admin-close"
|
||||
}}
|
||||
>
|
||||
<DButton
|
||||
class="btn-transparent"
|
||||
@label={{if
|
||||
@topic.closed
|
||||
"topic.actions.open"
|
||||
"topic.actions.close"
|
||||
}}
|
||||
@action={{fn this.onButtonAction "toggleClosed"}}
|
||||
@icon={{if @topic.closed "unlock" "lock"}}
|
||||
/>
|
||||
</li>
|
||||
{{/if}}
|
||||
|
||||
{{#if
|
||||
(and
|
||||
this.details.can_pin_unpin_topic
|
||||
(not this.isPrivateMessage)
|
||||
(or this.visible this.featured)
|
||||
)
|
||||
}}
|
||||
<li class="topic-admin-pin">
|
||||
<DButton
|
||||
class="btn-transparent"
|
||||
@label={{if
|
||||
this.featured
|
||||
"topic.actions.unpin"
|
||||
"topic.actions.pin"
|
||||
}}
|
||||
@action={{fn this.onButtonAction "showFeatureTopic"}}
|
||||
@icon="thumbtack"
|
||||
/>
|
||||
</li>
|
||||
{{/if}}
|
||||
|
||||
{{#if
|
||||
(and
|
||||
this.details.can_archive_topic
|
||||
(not this.isPrivateMessage)
|
||||
)
|
||||
}}
|
||||
<li class="topic-admin-archive">
|
||||
<DButton
|
||||
class="btn-transparent"
|
||||
@label={{if
|
||||
this.archived
|
||||
"topic.actions.unarchive"
|
||||
"topic.actions.archive"
|
||||
}}
|
||||
@action={{fn this.onButtonAction "toggleArchived"}}
|
||||
@icon="folder"
|
||||
/>
|
||||
</li>
|
||||
{{/if}}
|
||||
|
||||
{{#if this.details.can_toggle_topic_visibility}}
|
||||
<li class="topic-admin-visible">
|
||||
<DButton
|
||||
class="btn-transparent"
|
||||
@label={{if
|
||||
this.visible
|
||||
"topic.actions.invisible"
|
||||
"topic.actions.visible"
|
||||
}}
|
||||
@action={{fn this.onButtonAction "toggleVisibility"}}
|
||||
@icon={{if this.visible "far-eye-slash" "far-eye"}}
|
||||
/>
|
||||
</li>
|
||||
{{/if}}
|
||||
|
||||
{{#if (and this.details.can_convert_topic)}}
|
||||
<li class="topic-admin-convert">
|
||||
<DButton
|
||||
class="btn-transparent"
|
||||
@label={{if
|
||||
this.isPrivateMessage
|
||||
"topic.actions.make_public"
|
||||
"topic.actions.make_private"
|
||||
}}
|
||||
@action={{fn
|
||||
this.onButtonAction
|
||||
(if
|
||||
this.isPrivateMessage
|
||||
"convertToPublicTopic"
|
||||
"convertToPrivateMessage"
|
||||
)
|
||||
}}
|
||||
@icon={{if
|
||||
this.isPrivateMessage
|
||||
"comment"
|
||||
"envelope"
|
||||
}}
|
||||
/>
|
||||
</li>
|
||||
{{/if}}
|
||||
</ul>
|
||||
|
||||
<ul class="topic-admin-menu-time">
|
||||
{{#if this.currentUser.canManageTopic}}
|
||||
<li class="admin-topic-timer-update">
|
||||
<DButton
|
||||
class="btn-transparent"
|
||||
@label="topic.actions.timed_update"
|
||||
@action={{fn
|
||||
this.onButtonAction
|
||||
"showTopicTimerModal"
|
||||
}}
|
||||
@icon="far-clock"
|
||||
/>
|
||||
</li>
|
||||
|
||||
{{#if this.currentUser.staff}}
|
||||
<li class="topic-admin-change-timestamp">
|
||||
<DButton
|
||||
class="btn-transparent"
|
||||
@label="topic.change_timestamp.title"
|
||||
@action={{fn
|
||||
this.onButtonAction
|
||||
"showChangeTimestamp"
|
||||
}}
|
||||
@icon="calendar-alt"
|
||||
/>
|
||||
</li>
|
||||
{{/if}}
|
||||
|
||||
<li class="topic-admin-reset-bump-date">
|
||||
<DButton
|
||||
class="btn-transparent"
|
||||
@label="topic.actions.reset_bump_date"
|
||||
@action={{fn this.onButtonAction "resetBumpDate"}}
|
||||
@icon="anchor"
|
||||
/>
|
||||
</li>
|
||||
|
||||
<li class="topic-admin-slow-mode">
|
||||
<DButton
|
||||
class="btn-transparent"
|
||||
@label="topic.actions.slow_mode"
|
||||
@action={{fn
|
||||
this.onButtonAction
|
||||
"showTopicSlowModeUpdate"
|
||||
}}
|
||||
@icon="hourglass-start"
|
||||
/>
|
||||
</li>
|
||||
{{/if}}
|
||||
</ul>
|
||||
|
||||
{{#if (or this.currentUser.staff this.extraButtons.length)}}
|
||||
<ul class="topic-admin-menu-undefined">
|
||||
{{#if this.currentUser.staff}}
|
||||
<li class="topic-admin-moderation-history">
|
||||
<DButton
|
||||
class="btn-transparent"
|
||||
@label="review.moderation_history"
|
||||
@href={{this.topicModerationHistoryUrl}}
|
||||
@icon="list"
|
||||
/>
|
||||
</li>
|
||||
{{/if}}
|
||||
|
||||
{{#each this.extraButtons as |button|}}
|
||||
<li>
|
||||
<DButton
|
||||
@label={{button.label}}
|
||||
@translatedLabel={{button.translatedLabel}}
|
||||
@icon={{button.icon}}
|
||||
class={{concatClass
|
||||
"btn-transparent"
|
||||
button.className
|
||||
}}
|
||||
@action={{fn
|
||||
this.onExtraButtonAction
|
||||
button.action
|
||||
}}
|
||||
/>
|
||||
</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
{{#if
|
||||
(or
|
||||
this.currentUser.canManageTopic
|
||||
this.details.can_moderate_category
|
||||
)
|
||||
}}
|
||||
{{#if this.canDelete}}
|
||||
<dropdown.item class="topic-admin-delete">
|
||||
<DButton
|
||||
@label="topic.actions.delete"
|
||||
@action={{fn this.onButtonAction "deleteTopic"}}
|
||||
@icon="far-trash-alt"
|
||||
class="popup-menu-btn-danger btn-danger btn-transparent"
|
||||
/>
|
||||
</dropdown.item>
|
||||
{{else if this.canRecover}}
|
||||
<dropdown.item class="topic-admin-recover">
|
||||
<DButton
|
||||
class="btn-transparent"
|
||||
@label="topic.actions.recover"
|
||||
@action={{fn this.onButtonAction "recoverTopic"}}
|
||||
@icon="undo"
|
||||
/>
|
||||
</dropdown.item>
|
||||
{{/if}}
|
||||
</ul>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if this.details.can_close_topic}}
|
||||
<dropdown.item
|
||||
class={{if
|
||||
@topic.closed
|
||||
"topic-admin-open"
|
||||
"topic-admin-close"
|
||||
}}
|
||||
>
|
||||
<DButton
|
||||
class="btn-transparent"
|
||||
@label={{if
|
||||
@topic.closed
|
||||
"topic.actions.open"
|
||||
"topic.actions.close"
|
||||
}}
|
||||
@action={{fn this.onButtonAction "toggleClosed"}}
|
||||
@icon={{if @topic.closed "unlock" "lock"}}
|
||||
/>
|
||||
</dropdown.item>
|
||||
{{/if}}
|
||||
|
||||
{{#if
|
||||
(and
|
||||
this.details.can_pin_unpin_topic
|
||||
(not this.isPrivateMessage)
|
||||
(or this.visible this.featured)
|
||||
)
|
||||
}}
|
||||
<dropdown.item class="topic-admin-pin">
|
||||
<DButton
|
||||
class="btn-transparent"
|
||||
@label={{if
|
||||
this.featured
|
||||
"topic.actions.unpin"
|
||||
"topic.actions.pin"
|
||||
}}
|
||||
@action={{fn this.onButtonAction "showFeatureTopic"}}
|
||||
@icon="thumbtack"
|
||||
/>
|
||||
</dropdown.item>
|
||||
{{/if}}
|
||||
|
||||
{{#if
|
||||
(and
|
||||
this.details.can_archive_topic (not this.isPrivateMessage)
|
||||
)
|
||||
}}
|
||||
<dropdown.item class="topic-admin-archive">
|
||||
<DButton
|
||||
class="btn-transparent"
|
||||
@label={{if
|
||||
this.archived
|
||||
"topic.actions.unarchive"
|
||||
"topic.actions.archive"
|
||||
}}
|
||||
@action={{fn this.onButtonAction "toggleArchived"}}
|
||||
@icon="folder"
|
||||
/>
|
||||
</dropdown.item>
|
||||
{{/if}}
|
||||
|
||||
{{#if this.details.can_toggle_topic_visibility}}
|
||||
<dropdown.item class="topic-admin-visible">
|
||||
<DButton
|
||||
class="btn-transparent"
|
||||
@label={{if
|
||||
this.visible
|
||||
"topic.actions.invisible"
|
||||
"topic.actions.visible"
|
||||
}}
|
||||
@action={{fn this.onButtonAction "toggleVisibility"}}
|
||||
@icon={{if this.visible "far-eye-slash" "far-eye"}}
|
||||
/>
|
||||
</dropdown.item>
|
||||
{{/if}}
|
||||
|
||||
{{#if (and this.details.can_convert_topic)}}
|
||||
<dropdown.item class="topic-admin-convert">
|
||||
<DButton
|
||||
class="btn-transparent"
|
||||
@label={{if
|
||||
this.isPrivateMessage
|
||||
"topic.actions.make_public"
|
||||
"topic.actions.make_private"
|
||||
}}
|
||||
@action={{fn
|
||||
this.onButtonAction
|
||||
(if
|
||||
this.isPrivateMessage
|
||||
"convertToPublicTopic"
|
||||
"convertToPrivateMessage"
|
||||
)
|
||||
}}
|
||||
@icon={{if this.isPrivateMessage "comment" "envelope"}}
|
||||
/>
|
||||
</dropdown.item>
|
||||
{{/if}}
|
||||
|
||||
<dropdown.divider />
|
||||
|
||||
{{#if this.currentUser.canManageTopic}}
|
||||
<dropdown.item class="admin-topic-timer-update">
|
||||
<DButton
|
||||
class="btn-transparent"
|
||||
@label="topic.actions.timed_update"
|
||||
@action={{fn this.onButtonAction "showTopicTimerModal"}}
|
||||
@icon="far-clock"
|
||||
/>
|
||||
</dropdown.item>
|
||||
|
||||
{{#if this.currentUser.staff}}
|
||||
<dropdown.item class="topic-admin-change-timestamp">
|
||||
<DButton
|
||||
class="btn-transparent"
|
||||
@label="topic.change_timestamp.title"
|
||||
@action={{fn this.onButtonAction "showChangeTimestamp"}}
|
||||
@icon="calendar-alt"
|
||||
/>
|
||||
</dropdown.item>
|
||||
{{/if}}
|
||||
|
||||
<dropdown.item class="topic-admin-reset-bump-date">
|
||||
<DButton
|
||||
class="btn-transparent"
|
||||
@label="topic.actions.reset_bump_date"
|
||||
@action={{fn this.onButtonAction "resetBumpDate"}}
|
||||
@icon="anchor"
|
||||
/>
|
||||
</dropdown.item>
|
||||
|
||||
<dropdown.item class="topic-admin-slow-mode">
|
||||
<DButton
|
||||
class="btn-transparent"
|
||||
@label="topic.actions.slow_mode"
|
||||
@action={{fn
|
||||
this.onButtonAction
|
||||
"showTopicSlowModeUpdate"
|
||||
}}
|
||||
@icon="hourglass-start"
|
||||
/>
|
||||
</dropdown.item>
|
||||
|
||||
<dropdown.divider />
|
||||
{{/if}}
|
||||
|
||||
{{#if (or this.currentUser.staff this.extraButtons.length)}}
|
||||
{{#if this.currentUser.staff}}
|
||||
<dropdown.item class="topic-admin-moderation-history">
|
||||
<DButton
|
||||
class="btn-transparent"
|
||||
@label="review.moderation_history"
|
||||
@href={{this.topicModerationHistoryUrl}}
|
||||
@icon="list"
|
||||
/>
|
||||
</dropdown.item>
|
||||
{{/if}}
|
||||
|
||||
{{#each this.extraButtons as |button|}}
|
||||
<dropdown.item>
|
||||
<DButton
|
||||
@label={{button.label}}
|
||||
@translatedLabel={{button.translatedLabel}}
|
||||
@icon={{button.icon}}
|
||||
class={{concatClass "btn-transparent" button.className}}
|
||||
@action={{fn this.onExtraButtonAction button.action}}
|
||||
/>
|
||||
</dropdown.item>
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
</DropdownMenu>
|
||||
</:content>
|
||||
</DMenu>
|
||||
</span>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import $ from "jquery";
|
||||
import { h } from "virtual-dom";
|
||||
import { addBulkDropdownButton } from "discourse/components/bulk-select-topics-dropdown";
|
||||
import {
|
||||
addApiImageWrapperButtonClickEvent,
|
||||
addComposerUploadHandler,
|
||||
|
@ -141,7 +142,6 @@ import {
|
|||
replaceIcon,
|
||||
} from "discourse-common/lib/icon-library";
|
||||
import { addImageWrapperButton } from "discourse-markdown-it/features/image-controls";
|
||||
import { addBulkDropdownButton } from "select-kit/components/bulk-select-topics-dropdown";
|
||||
import { CUSTOM_USER_SEARCH_OPTIONS } from "select-kit/components/user-chooser";
|
||||
import { modifySelectKit } from "select-kit/mixins/plugin-api";
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import EmberObject from "@ember/object";
|
||||
import BulkSelectTopicsDropdown from "discourse/components/bulk-select-topics-dropdown";
|
||||
import rawRenderGlimmer from "discourse/lib/raw-render-glimmer";
|
||||
import i18n from "discourse-common/helpers/i18n";
|
||||
import BulkSelectTopicsDropdown from "select-kit/components/bulk-select-topics-dropdown";
|
||||
|
||||
export default class extends EmberObject {
|
||||
get selectedCount() {
|
||||
|
|
|
@ -827,8 +827,8 @@ export default createWidget("post-menu", {
|
|||
this.menu.show(event.target, {
|
||||
identifier: "admin-post-menu",
|
||||
component: AdminPostMenu,
|
||||
extraClassName: "popup-menu",
|
||||
modalForMobile: true,
|
||||
autofocus: true,
|
||||
data: {
|
||||
scheduleRerender: this.scheduleRerender.bind(this),
|
||||
transformedPost: this.attrs,
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
import { render } from "@ember/test-helpers";
|
||||
import { module, test } from "qunit";
|
||||
import DropdownMenu from "discourse/components/dropdown-menu";
|
||||
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
|
||||
|
||||
module("Integration | Component | <DropdownMenu />", function (hooks) {
|
||||
setupRenderingTest(hooks);
|
||||
|
||||
test("dropdown menu", async function (assert) {
|
||||
await render(<template><DropdownMenu class="test" /></template>);
|
||||
|
||||
assert
|
||||
.dom("ul.dropdown-menu.test")
|
||||
.exists("it renders the dropdown menu with custom class");
|
||||
});
|
||||
|
||||
test("dropdown menu item", async function (assert) {
|
||||
await render(<template>
|
||||
<DropdownMenu as |dm|><dm.item class="test">test</dm.item></DropdownMenu>
|
||||
</template>);
|
||||
|
||||
assert
|
||||
.dom("li.dropdown-menu__item.test")
|
||||
.exists("it renders the item with custom class")
|
||||
.hasText("test");
|
||||
});
|
||||
|
||||
test("dropdown menu divider", async function (assert) {
|
||||
await render(<template>
|
||||
<DropdownMenu as |dm|><dm.divider class="test" /></DropdownMenu>
|
||||
</template>);
|
||||
|
||||
assert
|
||||
.dom("li.test hr.dropdown-menu__divider")
|
||||
.exists("it renders the divider with custom class");
|
||||
});
|
||||
});
|
|
@ -1,7 +1,9 @@
|
|||
import Component from "@glimmer/component";
|
||||
import { concat } from "@ember/helper";
|
||||
import { inject as service } from "@ember/service";
|
||||
import { and } from "truth-helpers";
|
||||
import DModal from "discourse/components/d-modal";
|
||||
import concatClass from "discourse/helpers/concat-class";
|
||||
import DFloatBody from "float-kit/components/d-float-body";
|
||||
|
||||
export default class DInlineFloat extends Component {
|
||||
|
@ -15,6 +17,10 @@ export default class DInlineFloat extends Component {
|
|||
@hideHeader={{true}}
|
||||
data-identifier={{@instance.options.identifier}}
|
||||
data-content
|
||||
class={{concatClass
|
||||
"fk-d-menu-modal"
|
||||
(concat @instance.options.identifier "-content")
|
||||
}}
|
||||
>
|
||||
{{#if @instance.options.component}}
|
||||
<@instance.options.component
|
||||
|
|
|
@ -99,6 +99,8 @@ export default class DMenu extends Component {
|
|||
(concat this.options.identifier "-content")
|
||||
}}
|
||||
@inline={{(isTesting)}}
|
||||
data-identifier={{@instance.options.identifier}}
|
||||
data-content
|
||||
>
|
||||
{{#if (has-block)}}
|
||||
{{yield this.componentArgs}}
|
||||
|
|
|
@ -48,4 +48,4 @@
|
|||
@import "user-stream-item";
|
||||
@import "user-stream";
|
||||
@import "widget-dropdown";
|
||||
@import "admin-post-menu";
|
||||
@import "dropdown-menu";
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
[data-content][data-identifier="admin-post-menu"] {
|
||||
.d-modal__body {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
ul {
|
||||
padding: 0.5rem;
|
||||
margin: 0;
|
||||
list-style: none;
|
||||
|
||||
li .btn {
|
||||
width: 100%;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
li {
|
||||
margin-bottom: 2px;
|
||||
border: none;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.btn {
|
||||
justify-content: left;
|
||||
text-align: left;
|
||||
width: 100%;
|
||||
padding: 0.5em;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,22 +1,16 @@
|
|||
.bookmark-menu-content {
|
||||
.bookmark-menu__body {
|
||||
background: var(--secondary);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
.dropdown-menu {
|
||||
padding: 0;
|
||||
min-width: 200px;
|
||||
}
|
||||
.bookmark-menu__actions {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.bookmark-menu__title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75em;
|
||||
background: var(--tertiary-low);
|
||||
color: var(--tertiary);
|
||||
padding: 0.75rem;
|
||||
padding: 0.75rem 1rem;
|
||||
font-weight: bold;
|
||||
|
||||
.d-icon {
|
||||
|
@ -25,7 +19,6 @@
|
|||
}
|
||||
|
||||
.bookmark-menu__row {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
|
||||
&:hover,
|
||||
|
@ -39,19 +32,18 @@
|
|||
}
|
||||
|
||||
.bookmark-menu__row-title {
|
||||
padding: 0.75rem;
|
||||
border-bottom: 1px solid var(--primary-low);
|
||||
padding: 0.75rem 1rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.bookmark-menu__row-btn {
|
||||
margin: 0;
|
||||
padding: 0.75rem !important;
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
justify-content: left !important;
|
||||
gap: 0.75em;
|
||||
gap: 0.75rem;
|
||||
color: var(--primary);
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
color: var(--primary) !important;
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
.dropdown-menu {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
list-style: none;
|
||||
|
||||
&__item {
|
||||
.btn {
|
||||
padding: 0.65rem 1rem;
|
||||
width: 100%;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
}
|
||||
|
||||
&__divider {
|
||||
margin: 0rem;
|
||||
}
|
||||
}
|
|
@ -3,3 +3,4 @@
|
|||
@import "user-stream-item";
|
||||
@import "more-topics";
|
||||
@import "bookmark-menu";
|
||||
@import "dropdown-menu";
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
.bookmark-menu {
|
||||
&__row {
|
||||
border-bottom: 1px solid var(--primary-low);
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
&__row-title {
|
||||
padding: 0.75rem;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
.dropdown-menu {
|
||||
&__item {
|
||||
.btn {
|
||||
padding: 0.75rem 1rem;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,7 +8,7 @@ module PageObjects
|
|||
end
|
||||
|
||||
def open?
|
||||
has_css?(".bookmark-menu__body")
|
||||
has_css?(".bookmark-menu-content")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -20,14 +20,12 @@ module PageObjects
|
|||
|
||||
def has_bulk_select_topics_dropdown?
|
||||
page.has_css?(
|
||||
"#{TOPIC_LIST_HEADER_SELECTOR} .bulk-select-topics div.bulk-select-topics-dropdown",
|
||||
"#{TOPIC_LIST_HEADER_SELECTOR} .bulk-select-topics .bulk-select-topics-dropdown",
|
||||
)
|
||||
end
|
||||
|
||||
def click_bulk_select_topics_dropdown
|
||||
find(
|
||||
"#{TOPIC_LIST_HEADER_SELECTOR} .bulk-select-topics div.bulk-select-topics-dropdown",
|
||||
).click
|
||||
find("#{TOPIC_LIST_HEADER_SELECTOR} .bulk-select-topics .bulk-select-topics-dropdown").click
|
||||
end
|
||||
|
||||
def click_bulk_button(name)
|
||||
|
@ -68,7 +66,7 @@ module PageObjects
|
|||
private
|
||||
|
||||
def bulk_select_dropdown_item(name)
|
||||
"#{TOPIC_LIST_HEADER_SELECTOR} .bulk-select-topics div.bulk-select-topics-dropdown li[data-value='#{name}']"
|
||||
".bulk-select-topics-dropdown-content li.dropdown-menu__item .btn.#{name}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -76,14 +76,14 @@ describe "Topic page", type: :system do
|
|||
|
||||
visit("/t/#{topic.slug}/#{topic.id}")
|
||||
|
||||
expect(".topic-admin-menu-button-container").to be_present
|
||||
expect(".toggle-admin-menu").to be_present
|
||||
|
||||
send_keys([:shift, "a"])
|
||||
|
||||
expect(page).to have_css(".topic-admin-popup-menu")
|
||||
expect(page).to have_css(".topic-admin-menu-content")
|
||||
|
||||
send_keys([:shift, "a"])
|
||||
|
||||
expect(page).to have_no_css(".topic-admin-popup-menu")
|
||||
expect(page).to have_no_css(".topic-admin-menu-content")
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue