diff --git a/contentcuration/contentcuration/frontend/channelEdit/components/ContentNodeContextMenu.vue b/contentcuration/contentcuration/frontend/channelEdit/components/ContentNodeContextMenu.vue deleted file mode 100644 index ea742b88eb..0000000000 --- a/contentcuration/contentcuration/frontend/channelEdit/components/ContentNodeContextMenu.vue +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/contentcuration/contentcuration/frontend/channelEdit/components/ContentNodeEditListItem.vue b/contentcuration/contentcuration/frontend/channelEdit/components/ContentNodeEditListItem.vue index 3794cf7dd9..9cffd76261 100644 --- a/contentcuration/contentcuration/frontend/channelEdit/components/ContentNodeEditListItem.vue +++ b/contentcuration/contentcuration/frontend/channelEdit/components/ContentNodeEditListItem.vue @@ -49,10 +49,10 @@ - - - - + + + - - + @@ -92,11 +90,9 @@ /> - - + @@ -113,7 +109,6 @@ import ContentNodeListItem from './ContentNodeListItem'; import ContentNodeOptions from './ContentNodeOptions'; - import ContentNodeContextMenu from './ContentNodeContextMenu'; import Checkbox from 'shared/views/form/Checkbox'; import IconButton from 'shared/views/IconButton'; import DraggableItem from 'shared/views/draggable/DraggableItem'; @@ -129,7 +124,6 @@ DraggableItem, ContentNodeListItem, ContentNodeOptions, - ContentNodeContextMenu, Checkbox, IconButton, }, @@ -164,11 +158,6 @@ default: false, }, }, - data() { - return { - activated: false, - }; - }, computed: { ...mapGetters('currentChannel', ['canEdit']), ...mapGetters('contentNode', [ @@ -186,7 +175,7 @@ }, }, active() { - return this.selected || this.activated || this.previewing; + return this.selected || this.previewing; }, contentNode() { return this.getContentNode(this.nodeId); diff --git a/contentcuration/contentcuration/frontend/channelEdit/components/ContentNodeListItem/index.vue b/contentcuration/contentcuration/frontend/channelEdit/components/ContentNodeListItem/index.vue index d2e7afbaba..5b954814c1 100644 --- a/contentcuration/contentcuration/frontend/channelEdit/components/ContentNodeListItem/index.vue +++ b/contentcuration/contentcuration/frontend/channelEdit/components/ContentNodeListItem/index.vue @@ -2,196 +2,190 @@ - - - - - + + + + + + + + + + + + {{ getTitle(node) }} + + + + + local_library + + + + + + + + + + + - - - - - {{ subtitle }} + - - - - - {{ getTitle(node) }} - - - + {{ category(node.categories) }} + + + + + + local_library - - - - - - - - - - - {{ subtitle }} - - {{ category(node.categories) }} - - - - - - - - local_library - - - {{ $formatNumber(node.coach_count) }} - - - - - {{ isTopic ? - $tr('hasCoachTooltip', { value: node.coach_count }) - : $tr('coachTooltip') - }} + + {{ $formatNumber(node.coach_count) }} - - - - - - - - - {{ levels(key) }} - + + + + {{ isTopic ? + $tr('hasCoachTooltip', { value: node.coach_count }) + : $tr('coachTooltip') + }} + + + + + + + + + {{ levels(key) }} - - - - - - - - - - - - - - - - {{ copyingMessage }} - - - - - - - - - - - + + + + + + + + + + + + - - + + + + + {{ copyingMessage }} + + + + + + + + + + - + @@ -210,7 +204,6 @@ import { RolesNames } from 'shared/leUtils/Roles'; import ImageOnlyThumbnail from 'shared/views/files/ImageOnlyThumbnail'; import ToggleText from 'shared/views/ToggleText'; - import ContextMenuCloak from 'shared/views/ContextMenuCloak'; import DraggableHandle from 'shared/views/draggable/DraggableHandle'; import { titleMixin, metadataTranslationMixin } from 'shared/mixins'; import { EffectAllowed } from 'shared/mixins/draggable/constants'; @@ -220,7 +213,6 @@ name: 'ContentNodeListItem', components: { DraggableHandle, - ContextMenuCloak, ImageOnlyThumbnail, ContentNodeValidator, ContentNodeChangedIcon, diff --git a/contentcuration/contentcuration/frontend/channelEdit/components/ContentNodeOptions.vue b/contentcuration/contentcuration/frontend/channelEdit/components/ContentNodeOptions.vue index ad50a809f8..c8cd119557 100644 --- a/contentcuration/contentcuration/frontend/channelEdit/components/ContentNodeOptions.vue +++ b/contentcuration/contentcuration/frontend/channelEdit/components/ContentNodeOptions.vue @@ -1,43 +1,14 @@ - - - - - - {{ option.label }} - - - - - - - - + + + + @@ -45,15 +16,11 @@ import { mapActions, mapGetters } from 'vuex'; import { RouteNames, TabNames, QuickEditModals } from '../constants'; - import MoveModal from './move/MoveModal'; import { withChangeTracker } from 'shared/data/changes'; import { RELATIVE_TREE_POSITIONS } from 'shared/data/constants'; export default { name: 'ContentNodeOptions', - components: { - MoveModal, - }, props: { nodeId: { type: String, @@ -67,11 +34,10 @@ type: Boolean, default: false, }, - }, - data() { - return { - moveModalOpen: false, - }; + isContextMenu: { + type: Boolean, + default: false, + }, }, computed: { ...mapGetters('currentChannel', ['canEdit', 'trashId']), @@ -113,7 +79,8 @@ label: this.$tr('move'), onClick: $event => { $event.stopPropagation(); - this.moveModalOpen = true; + this.trackAction('Move'); + this.setMoveNodesIds([this.nodeId]); }, condition: this.canEdit, }, @@ -197,6 +164,14 @@ .filter(group => group.some(option => option.condition)) .map(group => group.filter(option => option.condition)); }, + menuOptions() { + return this.groupedOptions.reduce((acc, group, idx) => { + if (idx > 0) { + acc.push({ type: 'divider' }); + } + return acc.concat(group); + }); + }, editLink() { return { name: RouteNames.CONTENTNODE_DETAILS, @@ -216,22 +191,6 @@ }; }, }, - watch: { - moveModalOpen(open) { - if (open) { - this.trackAction('Move'); - } - }, - }, - beforeMount() { - this.lastFocus = document.activeElement; - }, - mounted() { - this.focusFirstOption(); - }, - destroyed() { - this.lastFocus && this.lastFocus.focus(); - }, methods: { ...mapActions(['showSnackbar', 'clearSnackbar']), ...mapActions('contentNode', [ @@ -240,28 +199,15 @@ 'copyContentNode', 'waitForCopyingStatus', 'setQuickEditModal', + 'setMoveNodesIds', ]), ...mapActions('clipboard', ['copy']), - async focusFirstOption() { - const { optionsList } = this.$refs; - const firstOption = optionsList.$el.querySelector('a'); - let tries = 0; - while (document.activeElement !== firstOption && tries++ < 20) { - await new Promise(resolve => setTimeout(resolve, 0)); - firstOption.focus(); + handleSelect(option, $event) { + if (option.onClick) { + option.onClick($event); } - }, - checkTabBoundaries($event) { - const optionsList = this.$refs.optionsList; - const options = optionsList.$el.querySelectorAll('a'); - const index = Array.from(options).indexOf($event.target); - if ( - (index === 0 && $event.shiftKey) || - (index === options.length - 1 && !$event.shiftKey) - ) { - // destroy component - $event.preventDefault(); - this.$destroy(); + if (option.to) { + this.$router.push(option.to); } }, newTopicNode() { @@ -281,11 +227,6 @@ }); }); }, - moveNode(target) { - return this.moveContentNodes({ id__in: [this.nodeId], parent: target }).then( - this.$refs.moveModal.moveComplete - ); - }, getRemoveNodeRedirect() { // Returns a callback to do appropriate post-removal navigation const { detailNodeId, nodeId } = this.$route.params; diff --git a/contentcuration/contentcuration/frontend/channelEdit/components/StudioTree/StudioTree.vue b/contentcuration/contentcuration/frontend/channelEdit/components/StudioTree/StudioTree.vue index 162a5b9107..d101e2e624 100644 --- a/contentcuration/contentcuration/frontend/channelEdit/components/StudioTree/StudioTree.vue +++ b/contentcuration/contentcuration/frontend/channelEdit/components/StudioTree/StudioTree.vue @@ -20,141 +20,131 @@ @draggableDragLeave="dragLeave" > - - - + + - + + + keyboard_arrow_right + + + + + + + {{ node.resource_count ? "folder" : "folder_open" }} + + + {{ getTitle(node) }} + + + + + {{ getTitle(node) }} + + + {{ $tr('missingTitle') }} + + + + + + + + - + + + + - - - - keyboard_arrow_right - - - - - - - {{ node.resource_count ? "folder" : "folder_open" }} - - - {{ getTitle(node) }} - - - - - {{ getTitle(node) }} - - - {{ $tr('missingTitle') }} - - - - - - - - - - - - - - - - - - - - - - {{ getTitle(node) }} - - - - - - - - + + + + + + + + + {{ getTitle(node) }} + + + + + + @@ -186,12 +176,9 @@ import ContentNodeOptions from '../ContentNodeOptions'; import ContentNodeChangedIcon from '../ContentNodeChangedIcon'; import ContentNodeValidator from '../ContentNodeValidator'; - import ContentNodeContextMenu from '../ContentNodeContextMenu'; import ContentNodeCopyTaskProgress from '../../views/progress/ContentNodeCopyTaskProgress'; import { ContentKindsNames } from 'shared/leUtils/ContentKinds'; - import ContextMenuCloak from 'shared/views/ContextMenuCloak'; import LoadingText from 'shared/views/LoadingText'; - import IconButton from 'shared/views/IconButton'; import DraggableCollection from 'shared/views/draggable/DraggableCollection'; import DraggableItem from 'shared/views/draggable/DraggableItem'; import DraggableHandle from 'shared/views/draggable/DraggableHandle'; @@ -205,13 +192,10 @@ DraggableHandle, DraggableItem, DraggableCollection, - ContextMenuCloak, - ContentNodeContextMenu, ContentNodeOptions, ContentNodeChangedIcon, ContentNodeValidator, LoadingText, - IconButton, ContentNodeCopyTaskProgress, }, mixins: [titleMixin], @@ -258,7 +242,6 @@ draggableSize: 5, draggableExpanded: false, debouncedLoad: null, - showMenu: false, }; }, computed: { diff --git a/contentcuration/contentcuration/frontend/channelEdit/views/CurrentTopicView.vue b/contentcuration/contentcuration/frontend/channelEdit/views/CurrentTopicView.vue index b34e38ec7e..2a32170eac 100644 --- a/contentcuration/contentcuration/frontend/channelEdit/views/CurrentTopicView.vue +++ b/contentcuration/contentcuration/frontend/channelEdit/views/CurrentTopicView.vue @@ -11,16 +11,15 @@ {{ getTitle(item) }} - - - + + + - - + {{ getTitle(item) }} @@ -195,23 +194,18 @@ :text="$tr('editButton')" @click="editNodes([detailNodeId])" /> - - - + + - - + + !state.connection.online, }), ...mapGetters(['isAboutLicensesModalOpen']), - ...mapGetters('contentNode', ['getContentNode']), + ...mapGetters('contentNode', ['getContentNode', 'getMoveNodesIds']), ...mapGetters('currentChannel', ['currentChannel', 'canEdit', 'canManage', 'rootId']), rootNode() { return this.getContentNode(this.rootId); @@ -473,9 +481,23 @@ dropEffect() { return DropEffect.COPY; }, + moveNodeIds() { + return this.getMoveNodesIds(); + }, + moveModalDialog: { + get() { + return this.moveNodeIds && this.moveNodeIds.length > 0; + }, + set(value) { + if (!value) { + this.setMoveNodesIds([]); + } + }, + }, }, methods: { ...mapActions('channel', ['deleteChannel']), + ...mapActions('contentNode', ['setMoveNodesIds', 'moveContentNodes']), handleDelete() { this.deleteChannel(this.currentChannel.id).then(() => { localStorage.snackbar = this.$tr('channelDeletedSnackbar'); @@ -497,6 +519,11 @@ this.showPublishModal = true; this.trackClickEvent('Publish'); }, + moveNodes(target) { + return this.moveContentNodes({ id__in: [this.nodeId], parent: target }).then( + this.$refs.moveModal.moveComplete + ); + }, trackClickEvent(eventLabel) { this.$analytics.trackClick('channel_editor_toolbar', eventLabel); }, diff --git a/contentcuration/contentcuration/frontend/channelEdit/vuex/contentNode/actions.js b/contentcuration/contentcuration/frontend/channelEdit/vuex/contentNode/actions.js index fb83c910c4..7fa000d427 100644 --- a/contentcuration/contentcuration/frontend/channelEdit/vuex/contentNode/actions.js +++ b/contentcuration/contentcuration/frontend/channelEdit/vuex/contentNode/actions.js @@ -546,6 +546,10 @@ export async function checkSavingProgress( return Boolean(query); } +export function setMoveNodesIds(context, ids) { + context.commit('SET_MOVE_NODES', ids); +} + export function setQuickEditModal(context, open) { context.commit('SET_QUICK_EDIT_MODAL', open); } diff --git a/contentcuration/contentcuration/frontend/channelEdit/vuex/contentNode/getters.js b/contentcuration/contentcuration/frontend/channelEdit/vuex/contentNode/getters.js index b6567221f0..ba1259cf75 100644 --- a/contentcuration/contentcuration/frontend/channelEdit/vuex/contentNode/getters.js +++ b/contentcuration/contentcuration/frontend/channelEdit/vuex/contentNode/getters.js @@ -357,3 +357,9 @@ export function getQuickEditModalOpen(state) { return state.quickEditModalOpen; }; } + +export function getMoveNodesIds(state) { + return function() { + return state.moveNodes; + }; +} diff --git a/package.json b/package.json index c538549924..8822297f40 100644 --- a/package.json +++ b/package.json @@ -73,7 +73,7 @@ "jspdf": "https://github.com/parallax/jsPDF.git#b7a1d8239c596292ce86dafa77f05987bcfa2e6e", "jszip": "^3.10.1", "kolibri-constants": "^0.2.0", - "kolibri-design-system": "3.1.0", + "kolibri-design-system": "3.3.0", "lodash": "^4.17.21", "material-icons": "0.3.1", "mutex-js": "^1.1.5", diff --git a/yarn.lock b/yarn.lock index ba58c16c08..cd4d7d936d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9123,10 +9123,10 @@ kolibri-constants@^0.2.0: resolved "https://registry.yarnpkg.com/kolibri-constants/-/kolibri-constants-0.2.0.tgz#47c9d773894e23251ba5ac4db420822e45603142" integrity sha512-WYDMGDzB9gNxRbpX1O2cGe1HrJvLvSZGwMuAv6dqrxJgPf7iO+Hi40/1CXjHM7nk5CRt+hn5bqnMzCBmj1omPA== -kolibri-design-system@3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/kolibri-design-system/-/kolibri-design-system-3.1.0.tgz#b8cfeeba3c41b0d2c43b4098732367e6732763a8" - integrity sha512-Xynv24J0uKJFQvhTgbOOWZdRRUMO3NSsobCCrD6R6lvzUqCEqcrJTLgK0ls6LX0MZu2dzxMGA0riLZx4qwikJw== +kolibri-design-system@3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/kolibri-design-system/-/kolibri-design-system-3.3.0.tgz#728d9955d27782315fc7e5a49af7fca6f9e88c00" + integrity sha512-1X7LJc9LAUXQV2NmcfVVjRW7igezsgcNg/znY8hah0DAzu6OX+tZDn/yEfCwbDhdVkpwzELxjMLZMM5o9aeKgg== dependencies: "@vue/composition-api" "^1.7.2" aphrodite "https://github.com/learningequality/aphrodite/"
- - {{ copyingMessage }} - - -
+ + {{ copyingMessage }} + + +