diff --git a/frappe/desk/doctype/internal_wiki_page/internal_wiki_page.py b/frappe/desk/doctype/internal_wiki_page/internal_wiki_page.py index 3fba588343..a53473e1fe 100644 --- a/frappe/desk/doctype/internal_wiki_page/internal_wiki_page.py +++ b/frappe/desk/doctype/internal_wiki_page/internal_wiki_page.py @@ -35,10 +35,12 @@ def save_wiki_page(title, parent, sb_items, deleted_pages, new_widgets, blocks, doc.save() if json.loads(sb_items): - for d in json.loads(sb_items): + for seq, d in enumerate(json.loads(sb_items)): doc = frappe.get_doc('Internal Wiki Page', d.get('name')) - doc.sequence_id = d.get('sequence_id') + doc.sequence_id = seq + 1 + doc.parent_page = d.get('parent_page') or "" doc.save() + doc.title = title if json.loads(deleted_pages): for d in json.loads(deleted_pages): diff --git a/frappe/public/icons/timeless/symbol-defs.svg b/frappe/public/icons/timeless/symbol-defs.svg index 5e52336bfa..87d80eef03 100644 --- a/frappe/public/icons/timeless/symbol-defs.svg +++ b/frappe/public/icons/timeless/symbol-defs.svg @@ -57,6 +57,9 @@ + + + diff --git a/frappe/public/js/frappe/views/wiki.js b/frappe/public/js/frappe/views/wiki.js index 22036a8d2d..b0ec3c1882 100644 --- a/frappe/public/js/frappe/views/wiki.js +++ b/frappe/public/js/frappe/views/wiki.js @@ -86,11 +86,25 @@ frappe.views.Wiki = class Wiki { if (this.sidebar.find('.standard-sidebar-section')[0]) { this.sidebar.find('.standard-sidebar-section')[0].remove(); } - let sidebar_section = $(`
`); + let sidebar_section = $(`
`); + this.prepare_sidebar(items, sidebar_section, this.sidebar); + } + + prepare_sidebar(items, child_container, item_container) { + items.forEach(item => this.append_item(item, child_container)); + child_container.appendTo(item_container); + } + + append_item(item, container) { + let is_current_page = frappe.router.slug(item.name) == frappe.router.slug(this.get_page_to_show()) || item.name == this.new_page; + if (is_current_page) { + item.selected = true; + this.current_page_name = item.name; + } - const get_sidebar_item = function (item) { + const item_container = function (item) { return $(` -
+ `); }; - const make_sidebar_category_item = item => { - if (item.name == this.get_page_to_show()) { - item.selected = true; - this.current_page_name = item.name; - } - - const get_child_item = function (item) { - return $(` - - `); - }; - - const make_sidebar_child_item = item => { - - if (frappe.router.slug(item.name) == this.get_page_to_show() || item.name == this.new_page) { - child_item_section.classList.toggle("hidden"); - } + let $item_container = item_container(item); + let sidebar_control = $item_container.find('.sidebar-item-control'); - let $child_item = get_child_item(item); - let sidebar_control = $child_item.find('.sidebar-item-control'); - this.add_sidebar_actions(item, sidebar_control); - $child_item.appendTo(child_item_section); - this.sidebar_items[item.name] = $child_item; - }; - - let $item = get_sidebar_item(item); - let sidebar_control = $item.find('.sidebar-item-control'); - this.add_sidebar_actions(item, sidebar_control); - let $drop_icon = $(``); - $drop_icon.appendTo(sidebar_control); - let drop_icon = $item.find('.drop-icon').get(0); - let child_item_section = $item.find('.sidebar-child-item').get(0); - if (this.all_pages.some(e => e.parent_page == item.name)) { - drop_icon.classList.remove('hidden'); - drop_icon.addEventListener('click', () => { - child_item_section.classList.toggle("hidden"); - }); - } + this.add_sidebar_actions(item, sidebar_control); - let child_items = this.all_pages.filter(page => page.parent_page == item.name); - child_items.forEach(item => make_sidebar_child_item(item)); + let child_items = this.all_pages.filter(page => page.parent_page == item.name); + if (child_items.length > 0) { + let child_container = $(``); + this.prepare_sidebar(child_items, child_container, $item_container); + } - $item.appendTo(sidebar_section); - this.sidebar_items[item.name] = $item; - }; + $item_container.appendTo(container); + this.sidebar_items[item.name] = $item_container; - items.forEach(item => make_sidebar_category_item(item)); + if ($item_container.parent().hasClass('hidden') && is_current_page) { + $item_container.parent().toggleClass('hidden'); + } - sidebar_section.appendTo(this.sidebar); + let $drop_icon = $(``); + $drop_icon.appendTo(sidebar_control); + let drop_icon = $item_container.find('.drop-icon').get(0); + let child_item_section = $item_container.find('.sidebar-child-item').get(0); + if (this.all_pages.some(e => e.parent_page == item.name)) { + drop_icon.classList.remove('hidden'); + drop_icon.addEventListener('click', () => { + child_item_section.classList.toggle("hidden"); + let icon = $(drop_icon).find("use").attr("href")==="#icon-small-down" ? "#icon-small-up" : "#icon-small-down"; + $(drop_icon).find("use").attr("href", icon); + }); + } } show() { @@ -275,6 +258,7 @@ frappe.views.Wiki = class Wiki { .then(() => { this.undo = new Undo({ editor: this.editor }); this.undo.initialize({blocks: JSON.parse(this.content)}); + this.undo.readOnly = false; this.setup_customization_buttons(); this.show_sidebar_actions(); this.make_sidebar_sortable(); @@ -334,27 +318,28 @@ frappe.views.Wiki = class Wiki { make_sidebar_sortable() { let me = this; - this.sidebar_sortable = Sortable.create(this.page.sidebar.find(".standard-sidebar-section").get(0), { - handle: ".drag-handle", - draggable: ".standard-sidebar-item-container", - animation: 150, - onEnd: function (evt) { - let new_sb_items = []; - let old_sb_items = me.all_pages.filter(page => page.parent_page == '' || page.parent_page == null); - for (let page of evt.srcElement.childNodes) { - new_sb_items.push({ - name: page.attributes['item-name'].value, - sequence_id: parseInt(page.attributes['item-sequence'].value) - }); - } - me.sorted_sidebar_items = []; - new_sb_items.forEach((old, index) => { - if (old.sequence_id != old_sb_items[index].sequence_id) { - old.sequence_id = old_sb_items[index].sequence_id; - me.sorted_sidebar_items.push(old); + $('.nested-container').each( function() { + new Sortable(this, { + handle: ".drag-handle", + draggable: ".sidebar-item-container", + group: 'nested', + animation: 150, + fallbackOnBody: true, + swapThreshold: 0.65, + onEnd: function (evt) { + me.sorted_sidebar_items = []; + for (let page of $('.standard-sidebar-section').find('.sidebar-item-container')) { + let parent_page = ""; + if (page.closest('.nested-container').classList.contains('sidebar-child-item')) { + parent_page = page.parentElement.parentElement.attributes["item-name"].value; + } + me.sorted_sidebar_items.push({ + name: page.attributes['item-name'].value, + parent_page: parent_page + }); } - }); - } + } + }); }); } @@ -383,11 +368,10 @@ frappe.views.Wiki = class Wiki { () => { this.page.clear_primary_action(); this.page.clear_secondary_action(); + this.undo.readOnly = true; this.save_page(); this.editor.readOnly.toggle(); this.isReadOnly = true; - this.page_sortable.option("disabled", true); - this.sidebar_sortable.option("disabled", true); }, null, __("Saving") @@ -400,8 +384,6 @@ frappe.views.Wiki = class Wiki { this.page.clear_secondary_action(); this.editor.readOnly.toggle(); this.isReadOnly = true; - this.page_sortable.option("disabled", true); - this.sidebar_sortable.option("disabled", true); this.deleted_sidebar_items = []; this.reload(); frappe.show_alert({ message: __("Customizations Discarded"), indicator: "info" }); @@ -413,8 +395,17 @@ frappe.views.Wiki = class Wiki { const d = new frappe.ui.Dialog({ title: __('Set Title'), fields: [ - { label: __('Title'), fieldtype: 'Data', fieldname: 'title'}, - { label: __('Parent'), fieldtype: 'Select', fieldname: 'parent', options: this.all_pages.map(pages => pages.name)} + { + label: __('Title'), + fieldtype: 'Data', + fieldname: 'title' + }, + { + label: __('Parent'), + fieldtype: 'Select', + fieldname: 'parent', + options: this.all_pages.filter(page => !page.parent_page).map(page => page.name) + } ], primary_action_label: __('Create'), primary_action: (values) => { @@ -439,7 +430,6 @@ frappe.views.Wiki = class Wiki { } this.make_sidebar_sortable(); this.make_blocks_sortable(); - this.dirty = false; }); } }); @@ -447,7 +437,6 @@ frappe.views.Wiki = class Wiki { } initialize_editorjs(blocks) { - this.dirty = false; const data = { blocks: blocks || [] }; @@ -456,9 +445,6 @@ frappe.views.Wiki = class Wiki { autofocus: false, data, tunes: ['spacingTune'], - onChange: () => { - this.dirty = true; - }, readOnly: true, logLevel: 'ERROR' }); @@ -516,6 +502,6 @@ frappe.views.Wiki = class Wiki { reload() { this.setup_wiki_pages(); - this.dirty = false; + this.undo.readOnly = true; } }; diff --git a/frappe/public/scss/desk/wiki.scss b/frappe/public/scss/desk/wiki.scss index cb911611d8..e9dcb63c4e 100644 --- a/frappe/public/scss/desk/wiki.scss +++ b/frappe/public/scss/desk/wiki.scss @@ -14,8 +14,11 @@ .standard-sidebar-item { justify-content: space-between; + padding: 0px; .sidebar-item-control { + margin-right: 8px; + > * { align-self: center; margin-left: 3px; @@ -32,6 +35,11 @@ display: none; } + .drop-icon { + padding: 10px 12px 10px 0px; + margin-right: -8px; + } + svg { margin-right: 0; } @@ -44,15 +52,18 @@ .item-anchor { display: flex; overflow: hidden; + padding: 8px 0px 8px 12px; flex: 1; } } - .sidebar-child-item-container { - margin-left: 10px; + .sidebar-item-container { + .sidebar-item-container{ + margin-left: 10px; - .standard-sidebar-item { - justify-content: start; + .standard-sidebar-item { + justify-content: start; + } } } diff --git a/package.json b/package.json index 17f5a7b588..7a54c81149 100644 --- a/package.json +++ b/package.json @@ -60,7 +60,7 @@ "@editorjs/list": "^1.6.2", "babel-runtime": "^6.26.0", "chalk": "^2.3.2", - "editorjs-undo": "^0.1.5", + "editorjs-undo": "^0.1.6", "graphlib": "^2.1.8", "less": "^3.11.1", "rollup": "^1.2.2", diff --git a/yarn.lock b/yarn.lock index 8d0b04c622..0c3909dfb5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2265,10 +2265,10 @@ "jsbn" "~0.1.0" "safer-buffer" "^2.1.0" -"editorjs-undo@^0.1.5": - "integrity" "sha512-+qRmTe7Asn9KrsYHMCtNQi6rCBa+qrinJx/p7/Hj8K62HFzhMEuy7aMRbADd/KqcV2AsPVzgCj3PMHPmb6ZAkA==" - "resolved" "https://registry.npmjs.org/editorjs-undo/-/editorjs-undo-0.1.5.tgz" - "version" "0.1.5" +"editorjs-undo@^0.1.6": + "integrity" "sha512-zVHPnBf2mcI8hWT9Eu8H3bGDEcMj4gppXbQjJW11Aa8Kdy2SVBGhM6fS59OUlBsm8iHWLxuoG2NUIfy9Rd30sw==" + "resolved" "https://registry.npmjs.org/editorjs-undo/-/editorjs-undo-0.1.6.tgz" + "version" "0.1.6" "ee-first@1.1.1": "integrity" "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="