diff --git a/addons/website/models/website.py b/addons/website/models/website.py
index 888c876a930..520e96c66d0 100644
--- a/addons/website/models/website.py
+++ b/addons/website/models/website.py
@@ -10,7 +10,7 @@ from werkzeug import urls
from werkzeug.exceptions import NotFound
from odoo import api, fields, models, tools
-from odoo.addons.http_routing.models.ir_http import slugify
+from odoo.addons.http_routing.models.ir_http import slugify, _guess_mimetype
from odoo.addons.website.models.ir_http import sitemap_qs2dom
from odoo.addons.portal.controllers.portal import pager
from odoo.tools import pycompat
@@ -136,6 +136,10 @@ class Website(models.Model):
})
return result
+ @api.model
+ def guess_mimetype(self):
+ return _guess_mimetype()
+
def get_unique_path(self, page_url):
""" Given an url, return that url suffixed by counter if it already exists
:param page_url : the url to be checked for uniqueness
@@ -194,20 +198,21 @@ class Website(models.Model):
website_id = self._context.get('website_id')
url = page.url
-
- page_key = _('Page')
-
# search for website_page with link
website_page_search_dom = [
'|', ('website_ids', 'in', website_id), ('website_ids', '=', False), ('view_id.arch_db', 'ilike', url)
]
pages = self.env['website.page'].search(website_page_search_dom)
+ page_key = _('Page')
+ if len(pages) > 1:
+ page_key = _('Pages')
page_view_ids = []
for page in pages:
dependencies.setdefault(page_key, [])
dependencies[page_key].append({
'text': _('Page %s contains a link to this page') % page.url,
- 'link': page.url
+ 'item': page.name,
+ 'link': page.url,
})
page_view_ids.append(page.view_id.id)
@@ -217,23 +222,85 @@ class Website(models.Model):
('arch_db', 'ilike', url), ('id', 'not in', page_view_ids)
]
views = self.env['ir.ui.view'].search(page_search_dom)
+ view_key = _('Template')
+ if len(views) > 1:
+ view_key = _('Templates')
for view in views:
- dependencies.setdefault(page_key, [])
- dependencies[page_key].append({
- 'text': _('Template %s (id:%s) contains a link to this page') % (view.key or view.name, view.id),
- 'link': '#'
+ dependencies.setdefault(view_key, [])
+ dependencies[view_key].append({
+ 'text': _('Template %s (id:%s) contains a link to this page') % (view.key or view.name, view.id),
+ 'link': '/web#id=%s&view_type=form&model=ir.ui.view' % view.id,
+ 'item': _('%s (id:%s)') % (view.key or view.name, view.id),
})
# search for menu with link
menu_search_dom = [
'|', ('website_id', '=', website_id), ('website_id', '=', False), ('url', 'ilike', '%s' % url)
]
- menu_key = _('Menu')
menus = self.env['website.menu'].search(menu_search_dom)
+ menu_key = _('Menu')
+ if len(menus) > 1:
+ menu_key = _('Menus')
for menu in menus:
dependencies.setdefault(menu_key, []).append({
'text': _('This page is in the menu %s') % menu.name,
- 'link': False
+ 'link': '/web#id=%s&view_type=form&model=website.menu' % menu.id,
+ 'item': menu.name,
+ })
+
+ return dependencies
+
+ @api.model
+ def page_search_key_dependencies(self, page_id=False):
+ """ Search dependencies just for information. It will not catch 100%
+ of dependencies and False positive is more than possible
+ Each module could add dependences in this dict
+ :returns a dictionnary where key is the 'categorie' of object related to the given
+ view, and the value is the list of text and link to the resource using given page
+ """
+ dependencies = {}
+ if not page_id:
+ return dependencies
+
+ page = self.env['website.page'].browse(int(page_id))
+ website_id = self._context.get('website_id')
+ key = page.key
+
+ # search for website_page with link
+ website_page_search_dom = [
+ '|', ('website_ids', 'in', website_id), ('website_ids', '=', False), ('view_id.arch_db', 'ilike', key),
+ ('id', '!=', page.id),
+ ]
+ pages = self.env['website.page'].search(website_page_search_dom)
+ page_key = _('Page')
+ if len(pages) > 1:
+ page_key = _('Pages')
+ page_view_ids = []
+ for p in pages:
+ dependencies.setdefault(page_key, [])
+ dependencies[page_key].append({
+ 'text': _('Page %s is calling this file') % p.url,
+ 'item': p.name,
+ 'link': p.url,
+ })
+ page_view_ids.append(p.view_id.id)
+
+ # search for ir_ui_view (not from a website_page) with link
+ page_search_dom = [
+ '|', ('website_id', '=', website_id), ('website_id', '=', False),
+ ('arch_db', 'ilike', key), ('id', 'not in', page_view_ids),
+ ('id', '!=', page.view_id.id),
+ ]
+ views = self.env['ir.ui.view'].search(page_search_dom)
+ view_key = _('Template')
+ if len(views) > 1:
+ view_key = _('Templates')
+ for view in views:
+ dependencies.setdefault(view_key, [])
+ dependencies[view_key].append({
+ 'text': _('Template %s (id:%s) is calling this file') % (view.key or view.name, view.id),
+ 'item': _('%s (id:%s)') % (view.key or view.name, view.id),
+ 'link': '/web#id=%s&view_type=form&model=ir.ui.view' % view.id,
})
return dependencies
diff --git a/addons/website/static/src/js/menu/content.js b/addons/website/static/src/js/menu/content.js
index b2408c3b571..ccba660466f 100644
--- a/addons/website/static/src/js/menu/content.js
+++ b/addons/website/static/src/js/menu/content.js
@@ -19,6 +19,7 @@ var PagePropertiesDialog = widget.Dialog.extend({
['/website/static/src/xml/website.pageProperties.xml']
),
events: _.extend({}, widget.Dialog.prototype.events, {
+ 'keyup input#page_name': '_onNameChanged',
'keyup input#page_url': '_onUrlChanged',
'change input#create_redirect': '_onCreateRedirectChanged',
}),
@@ -90,19 +91,39 @@ var PagePropertiesDialog = widget.Dialog.extend({
this.$(".ask_for_redirect").hide();
this.$(".redirect_type").hide();
+ this.$(".warn_about_call").hide();
- //TODO: remove.html() & set self.var & display in view instead of controller (here)
this._getPageDependencies(self.page_id, context)
.then(function (dependencies) {
- var dep = [];
- _.each(dependencies, function( value, index ) {
- if (dependencies[index].length > 0) {
- dep.push(dependencies[index].length + ' ' + index.toLowerCase() + (dependencies[index].length > 1 ? 's': ''));
+ var dep_text = [];
+ _.each(dependencies, function(value, index){
+ if (value.length > 0) {
+ dep_text.push(value.length + ' ' + index.toLowerCase());
}
});
- if (dep.length > 0) {
- $("#dependencies_redirect").html("(" + _("used in") + " " + dep.join(", ") + ")");
- }
+ dep_text = dep_text.join(', ');
+ $('#dependencies_redirect').html(qweb.render('website.show_page_dependencies', { dependencies: dependencies, dep_text: dep_text }));
+ $('#dependencies_redirect [data-toggle="popover"]').popover({
+ container: 'body'
+ });
+ });
+ this._getSupportedMimetype(context)
+ .then(function (mimetypes) {
+ self.supportedMimetype = mimetypes;
+ });
+ this._getPageKeyDependencies(self.page_id, context)
+ .then(function (dependencies) {
+ var dep_text = [];
+ _.each(dependencies, function(value, index){
+ if (value.length > 0) {
+ dep_text.push(value.length + ' ' + index.toLowerCase());
+ }
+ });
+ dep_text = dep_text.join(', ');
+ $('.warn_about_call').html(qweb.render('website.show_page_key_dependencies', { dependencies: dependencies, dep_text: dep_text }));
+ $('.warn_about_call [data-toggle="popover"]').popover({
+ container: 'body'
+ });
});
var l10n = _t.database.parameters;
@@ -133,6 +154,13 @@ var PagePropertiesDialog = widget.Dialog.extend({
return this._super.apply(this, arguments);
},
+ /**
+ * @override
+ */
+ destroy: function(){
+ $('.popover').popover('hide');
+ return this._super.apply(this, arguments);
+ },
//--------------------------------------------------------------------------
// Public
@@ -184,7 +212,7 @@ var PagePropertiesDialog = widget.Dialog.extend({
//--------------------------------------------------------------------------
/**
- * Retrieves the page dependencies for the given object id.
+ * Retrieves the page URL dependencies for the given object id.
*
* @private
* @param {integer} moID
@@ -199,6 +227,36 @@ var PagePropertiesDialog = widget.Dialog.extend({
context: context,
});
},
+ /**
+ * Retrieves the page's key dependencies for the given object id.
+ *
+ * @private
+ * @param {integer} moID
+ * @param {Object} context
+ * @returns {Deferred}
+ */
+ _getPageKeyDependencies: function (moID, context) {
+ return this._rpc({
+ model: 'website',
+ method: 'page_search_key_dependencies',
+ args: [moID],
+ context: context,
+ });
+ },
+ /**
+ * Retrieves supported mimtype
+ *
+ * @private
+ * @param {Object} context
+ * @returns {Deferred}
+ */
+ _getSupportedMimetype: function (context) {
+ return this._rpc({
+ model: 'website',
+ method: 'guess_mimetype',
+ context: context,
+ });
+ },
/**
* Returns information about the page main object.
*
@@ -227,6 +285,20 @@ var PagePropertiesDialog = widget.Dialog.extend({
this.$(".ask_for_redirect").hide();
}
},
+ _onNameChanged: function () {
+ var name = this.$('input#page_name').val();
+ //If the file type is a supported mimetype, check if it is t-called. If so, warn user
+ //Note: different from page_search_dependencies which check only for url and not key
+ var ext = '.' + this.page.name.split('.').pop();
+ if(ext in this.supportedMimetype && ext != '.html'){
+ if (name != this.page.name) {
+ this.$(".warn_about_call").show();
+ }
+ else {
+ this.$(".warn_about_call").hide();
+ }
+ }
+ },
_onCreateRedirectChanged: function () {
var createRedirect = this.$('input#create_redirect').prop('checked');
if (createRedirect) {
diff --git a/addons/website/static/src/less/website.ui.components.less b/addons/website/static/src/less/website.ui.components.less
index 7f85829460a..8cbf1ba7d98 100644
--- a/addons/website/static/src/less/website.ui.components.less
+++ b/addons/website/static/src/less/website.ui.components.less
@@ -453,8 +453,13 @@ body .modal {
}
// Pages Management
-.o_page_management_info .o_switch{
- padding-top: 7px;
+.o_page_management_info{
+ .o_switch{
+ padding-top: 7px;
+ }
+}
+.popover_dep{
+ overflow-x: auto;
}
#edit_website_pages{
.fa-check{
diff --git a/addons/website/static/src/xml/website.pageProperties.xml b/addons/website/static/src/xml/website.pageProperties.xml
index b7b3b337d91..3746e294b0d 100644
--- a/addons/website/static/src/xml/website.pageProperties.xml
+++ b/addons/website/static/src/xml/website.pageProperties.xml
@@ -1,5 +1,39 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ It looks like your file is being called by
+ .
+ Changing its name will break these calls.
+
+
+
+
+
+
+
+ (could be used in )
+
+
+
+
+