diff --git a/addons/website/models/website_page.py b/addons/website/models/website_page.py index 05d1879f897..c3e01a1d34e 100644 --- a/addons/website/models/website_page.py +++ b/addons/website/models/website_page.py @@ -150,19 +150,24 @@ class Page(models.Model): return super(Page, self).copy(default=default) @api.model - def clone_page(self, page_id, clone_menu=True): + def clone_page(self, page_id, page_name=None, clone_menu=True): """ Clone a page, given its identifier :param page_id : website.page identifier """ page = self.browse(int(page_id)) - new_page = page.copy(dict(name=page.name, website_id=self.env['website'].get_current_website().id)) + copy_param = dict(name=page_name or page.name, website_id=self.env['website'].get_current_website().id) + if page_name: + page_url = '/' + slugify(page_name, max_length=1024, path=True) + copy_param['url'] = self.env['website'].get_unique_path(page_url) + + new_page = page.copy(copy_param) # Should not clone menu if the page was cloned from one website to another # Eg: Cloning a generic page (no website) will create a page with a website, we can't clone menu (not same container) if clone_menu and new_page.website_id == page.website_id: menu = self.env['website.menu'].search([('page_id', '=', page_id)], limit=1) if menu: # If the page being cloned has a menu, clone it too - menu.copy({'url': new_page.url, 'name': menu.name, 'page_id': new_page.id}) + menu.copy({'url': new_page.url, 'name': new_page.name, 'page_id': new_page.id}) return new_page.url + '?enable_editor=1' diff --git a/addons/website/static/src/js/menu/content.js b/addons/website/static/src/js/menu/content.js index b8743f27932..d8be9ba80ff 100644 --- a/addons/website/static/src/js/menu/content.js +++ b/addons/website/static/src/js/menu/content.js @@ -44,22 +44,32 @@ var PagePropertiesDialog = weWidgets.Dialog.extend({ var buttons = [ {text: _t("Save"), classes: 'btn-primary', click: this.save}, - {text: _t("Discard"), close: true}, + {text: _t("Discard"), classes: 'mr-auto', close: true}, ]; if (options.fromPageManagement) { buttons.push({ text: _t("Go To Page"), icon: 'fa-globe', - classes: 'btn-link float-right', + classes: 'btn-link', click: function (e) { window.location.href = '/' + self.page.url; }, }); } + buttons.push({ + text: _t("Duplicate Page"), + icon: 'fa-clone', + classes: 'btn-link', + click: function (e) { + // modal('hide') will break the rpc, so hide manually + this.$el.closest('.modal').addClass('d-none'); + _clonePage.call(this, self.page_id); + }, + }); buttons.push({ text: _t("Delete Page"), icon: 'fa-trash', - classes: 'btn-link float-right', + classes: 'btn-link', click: function (e) { _deletePage.call(this, self.page_id, options.fromPageManagement); }, @@ -985,13 +995,7 @@ var PageManagement = Widget.extend({ }, _onClonePageButtonClick: function (ev) { var pageId = $(ev.currentTarget).data('id'); - this._rpc({ - model: 'website.page', - method: 'clone_page', - args: [pageId], - }).then(function (path) { - window.location.href = path; - }); + _clonePage.call(this, pageId); }, _onDeletePageButtonClick: function (ev) { var pageId = $(ev.currentTarget).data('id'); @@ -1040,6 +1044,33 @@ function _deletePage(pageId, fromPageManagement) { }, reject); }); } +/** + * Duplicate the page after showing the wizard to enter new page name. + * + * @private + * @param {integer} pageId - The ID of the page to be duplicate + * + */ +function _clonePage(pageId) { + var self = this; + new Promise(function (resolve, reject) { + Dialog.confirm(this, undefined, { + title: _t("Duplicate Page"), + $content: $(qweb.render('website.duplicate_page_action_dialog')), + confirm_callback: function () { + var new_page_name = this.$('#page_name').val(); + return self._rpc({ + model: 'website.page', + method: 'clone_page', + args: [pageId, new_page_name], + }).then(function (path) { + window.location.href = path; + }).guardedCatch(reject); + }, + cancel_callback: reject, + }).on('closed', null, reject); + }); +} websiteNavbarData.websiteNavbarRegistry.add(ContentMenu, '#content-menu'); websiteRootData.websiteRootRegistry.add(PageManagement, '#list_website_pages'); diff --git a/addons/website/static/src/xml/website.xml b/addons/website/static/src/xml/website.xml index d4193d7cbc2..a8af566ecfb 100644 --- a/addons/website/static/src/xml/website.xml +++ b/addons/website/static/src/xml/website.xml @@ -76,4 +76,13 @@ + +
+
+ +
+ +
+
+
diff --git a/addons/website/tests/test_page.py b/addons/website/tests/test_page.py index 09f39074c89..8bcda96f7e2 100644 --- a/addons/website/tests/test_page.py +++ b/addons/website/tests/test_page.py @@ -60,7 +60,7 @@ class TestPage(common.TransactionCase): total_pages = Page.search_count([]) total_menus = Menu.search_count([]) # Copying a specific page should create a new page with an unique URL (suffixed by -X) - Page.clone_page(self.page_specific.id, True) + Page.clone_page(self.page_specific.id, clone_menu=True) cloned_page = Page.search([('url', '=', '/page_specific-1')]) cloned_menu = Menu.search([('url', '=', '/page_specific-1')]) self.assertEqual(len(cloned_page), 1, "A page with an URL /page_specific-1 should've been created") @@ -69,19 +69,27 @@ class TestPage(common.TransactionCase): self.assertEqual(len(cloned_menu), 1, "A specific page (with a menu) being cloned should have it's menu also cloned") self.assertEqual(cloned_menu.page_id, cloned_page, "The new cloned menu and the new cloned page should be linked (m2o)") self.assertEqual(Menu.search_count([]), total_menus + 1, "Should have cloned the page menu") + Page.clone_page(self.page_specific.id, page_name="about-us", clone_menu=True) + cloned_page_about_us = Page.search([('url', '=', '/about-us')]) + cloned_menu_about_us = Menu.search([('url', '=', '/about-us')]) + self.assertEqual(len(cloned_page_about_us), 1, "A page with an URL /about-us should've been created") + self.assertEqual(len(cloned_menu_about_us), 1, "A specific page (with a menu) being cloned should have it's menu also cloned") + self.assertEqual(cloned_menu_about_us.page_id, cloned_page_about_us, "The new cloned menu and the new cloned page should be linked (m2o)") + # It should also copy its menu with new url/name/page_id (if the page has a menu) + self.assertEqual(Menu.search_count([]), total_menus + 2, "Should have cloned the page menu") total_pages = Page.search_count([]) total_menus = Menu.search_count([]) # Copying a generic page should create a specific page with same URL - Page.clone_page(self.page_1.id, True) + Page.clone_page(self.page_1.id, clone_menu=True) cloned_generic_page = Page.search([('url', '=', '/page_1'), ('id', '!=', self.page_1.id), ('website_id', '!=', False)]) self.assertEqual(len(cloned_generic_page), 1, "A generic page being cloned should create a specific one for the current website") self.assertEqual(cloned_generic_page.url, self.page_1.url, "The URL of the cloned specific page should be the same as the generic page it has been cloned from") self.assertEqual(Page.search_count([]), total_pages + 1, "Should have cloned the generic page as a specific page for this website") self.assertEqual(Menu.search_count([]), total_menus, "It should not create a new menu as the generic page's menu belong to another website") # Except if the URL already exists for this website (its the case now that we already cloned it once) - Page.clone_page(self.page_1.id, True) + Page.clone_page(self.page_1.id, clone_menu=True) cloned_generic_page_2 = Page.search([('url', '=', '/page_1-1'), ('id', '!=', self.page_1.id)]) self.assertEqual(len(cloned_generic_page_2), 1, "A generic page being cloned should create a specific page with a new URL if there is already a specific page with that URL")