diff options
| author | Xavier Morel <xmo@openerp.com> | 2013-09-23 14:03:28 +0200 |
|---|---|---|
| committer | Xavier Morel <xmo@openerp.com> | 2013-09-23 14:03:28 +0200 |
| commit | 89fc31a633562dbbf046ee48cd943b2eb63c37d0 (patch) | |
| tree | c835cbdad281bb200e00b05ea3574351a42f3bc6 /addons/website/static/src/js | |
| parent | be4b1b9b599d2dea07f68908b56a2c84ab8e5e5f (diff) | |
| parent | 6788b91af4ae0b116b55af3cb0c5ecf2a16acdac (diff) | |
[MERGE] from trunk
bzr revid: xmo@openerp.com-20130923120328-0wgd7wxhl1y5qyhr
Diffstat (limited to 'addons/website/static/src/js')
| -rw-r--r-- | addons/website/static/src/js/website.ace.js | 146 | ||||
| -rw-r--r-- | addons/website/static/src/js/website.editor.js | 103 | ||||
| -rw-r--r-- | addons/website/static/src/js/website.mobile.js | 2 | ||||
| -rw-r--r-- | addons/website/static/src/js/website.seo.js | 191 | ||||
| -rw-r--r-- | addons/website/static/src/js/website.snippets.js | 715 |
5 files changed, 792 insertions, 365 deletions
diff --git a/addons/website/static/src/js/website.ace.js b/addons/website/static/src/js/website.ace.js index fd26c50aefd..206813f237b 100644 --- a/addons/website/static/src/js/website.ace.js +++ b/addons/website/static/src/js/website.ace.js @@ -3,20 +3,33 @@ var globalEditor; + var hash = "#advanced-view-editor"; + var website = openerp.website; website.templates.push('/website/static/src/xml/website.ace.xml'); + website.ready().then(function () { + if (window.location.hash.indexOf(hash) >= 0) { + launch(); + } + }); + + function launch () { + if (globalEditor) { + globalEditor.open(); + } else { + globalEditor = new website.ace.ViewEditor(this); + globalEditor.appendTo($(document.body)); + } + } + website.EditorBar.include({ events: _.extend({}, website.EditorBar.prototype.events, { 'click a[data-action=ace]': 'launchAce', }), - launchAce: function () { - if (globalEditor) { - globalEditor.open(); - } else { - globalEditor = new website.ace.ViewEditor(this); - globalEditor.appendTo($(document.body)); - } + launchAce: function (e) { + e.preventDefault(); + launch(); }, }); @@ -55,88 +68,143 @@ website.ace.ViewEditor = openerp.Widget.extend({ template: 'website.ace_view_editor', events: { - 'change #ace-view-list': 'displayView', - 'click button[data-action=save]': 'saveView', + 'change #ace-view-list': 'displaySelectedView', + 'click button[data-action=save]': 'saveViews', 'click button[data-action=format]': 'formatXml', 'click button[data-action=close]': 'close', }, + init: function (parent) { + this.buffers = {}; + this._super(parent); + }, start: function () { var self = this; + self.aceEditor = ace.edit(self.$('#ace-view-editor')[0]); + self.aceEditor.setTheme("ace/theme/monokai"); var viewId = $(document.documentElement).data('view-xmlid'); openerp.jsonRpc('/website/customize_template_get', 'call', { 'xml_id': viewId, 'optional': false, }).then(function (views) { - self.loadViewList.call(self, views); + self.loadViews.call(self, views); + self.open.call(self); }); - this.$el.hover(); - }, - selectedViewId: function () { - return parseInt(this.$('#ace-view-list').val(), 10); }, - loadViewList: function (views) { + loadViews: function (views) { + var self = this; var activeViews = _.filter(views, function (view) { return view.active; }); - var $viewList = this.$('#ace-view-list'); + var $viewList = self.$('#ace-view-list'); _.each(activeViews, function (view) { if (view.id) { - new website.ace.ViewOption(this, view).appendTo($viewList); + new website.ace.ViewOption(self, view).appendTo($viewList); + self.loadView(view.id); } }); - var editor = ace.edit(this.$('#ace-view-editor')[0]); - editor.setTheme("ace/theme/monokai"); - this.aceEditor = editor; - this.open(); }, - displayView: function () { - var editor = this.aceEditor; + loadView: function (id) { + var viewId = parseInt(id, 10); + var self = this; openerp.jsonRpc('/web/dataset/call', 'call', { model: 'ir.ui.view', method: 'read', - args: [[this.selectedViewId()], ['arch'], website.get_context()], + args: [[viewId], ['arch'], website.get_context()], }).then(function(result) { - var xml = new website.ace.XmlDocument(result[0].arch); - var editingSession = new ace.EditSession(xml.xml); + var editingSession = self.buffers[viewId] = new ace.EditSession(result[0].arch);; editingSession.setMode("ace/mode/xml"); editingSession.setUndoManager(new ace.UndoManager()); - editor.setSession(editingSession); + editingSession.on("change", function () { + setTimeout(function () { + var $option = self.$('#ace-view-list').find('[value='+viewId+']'); + var bufferName = $option.text(); + var dirtyMarker = " (unsaved changes)"; + var isDirty = editingSession.getUndoManager().hasUndo(); + if (isDirty && bufferName.indexOf(dirtyMarker) < 0) { + $option.text(bufferName + dirtyMarker); + } else if (!isDirty && bufferName.indexOf(dirtyMarker) > 0) { + $option.text(bufferName.substring(0, bufferName.indexOf(dirtyMarker))); + } + }, 1); + }); + if (viewId === self.selectedViewId()) { + self.displayView.call(self, viewId); + } }); }, + selectedViewId: function () { + return parseInt(this.$('#ace-view-list').val(), 10); + }, + displayView: function (id) { + var viewId = parseInt(id, 10); + var editingSession = this.buffers[viewId]; + if (editingSession) { + this.aceEditor.setSession(editingSession); + } + }, + displaySelectedView: function () { + this.displayView(this.selectedViewId()); + this.updateHash(); + }, formatXml: function () { var xml = new website.ace.XmlDocument(this.aceEditor.getValue()); this.aceEditor.setValue(xml.format()); }, - saveView: function () { + saveViews: function () { var self = this; - var xml = new website.ace.XmlDocument(this.aceEditor.getValue()); + var toSave = _.filter(_.map(self.buffers, function (editingSession, viewId) { + return { + id: parseInt(viewId, 10), + isDirty: editingSession.getUndoManager().hasUndo(), + text: editingSession.getValue(), + }; + }), function (session) { + return session.isDirty; + }); + var requests = _.map(toSave, self.saveView); + $.when.apply($, requests).then(function () { + self.reloadPage.call(self); + }).fail(function (source, error) { + var message = (error.data.arguments[0] === "Access Denied") ? "Access denied: please sign in" : error.message; + self.displayError.call(self, message); + }); + }, + saveView: function (session) { + var xml = new website.ace.XmlDocument(session.text); if (xml.isWellFormed()) { - openerp.jsonRpc('/web/dataset/call', 'call', { + return openerp.jsonRpc('/web/dataset/call', 'call', { model: 'ir.ui.view', method: 'write', - args: [[this.selectedViewId()], { 'arch': xml.xml }, website.get_context()], - }).then(function(result) { - self.reloadPage(); - }).fail(function (error) { - self.displayError(error); + args: [[session.id], { 'arch': xml.xml }, website.get_context()], }); } else { - self.displayError(); + return $.Deferred().fail("Malformed XML document"); } }, + updateHash: function () { + window.location.hash = hash + "?view=" + this.selectedViewId(); + }, reloadPage: function () { - // TODO Reload { header + div#wrap + footer } only + this.updateHash(); window.location.reload(); }, displayError: function (error) { // TODO Improve feedback (e.g. update 'Save' button + tooltip) - alert("Malformed XML document"); + alert(error); }, open: function () { this.$el.removeClass('oe_ace_closed').addClass('oe_ace_open'); - this.displayView(); + var curentHash = window.location.hash; + var indexOfView = curentHash.indexOf("?view="); + if (indexOfView >= 0) { + var viewId = parseInt(curentHash.substring(indexOfView + 6, curentHash.length), 10); + this.$('#ace-view-list').val(viewId).change(); + } else { + window.location.hash = hash; + } }, close: function () { + window.location.hash = ""; var self = this; this.$el.bind('transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd', function () { globalEditor = null; diff --git a/addons/website/static/src/js/website.editor.js b/addons/website/static/src/js/website.editor.js index 16443ac36c4..b2a93b9cfd6 100644 --- a/addons/website/static/src/js/website.editor.js +++ b/addons/website/static/src/js/website.editor.js @@ -236,10 +236,17 @@ this.rte = new website.RTE(this); this.rte.on('change', this, this.proxy('rte_changed')); + var instanceReady = false; + this.rte.on('instanceReady', this, function () { + clearTimeout(instanceReady); + instanceReady = setTimeout(function () { + self.trigger('rte:ready'); + }, 0); + }); return $.when( this._super.apply(this, arguments), - this.rte.prependTo(this.$('#website-top-edit .nav.pull-right')) + this.rte.appendTo(this.$('#website-top-edit .nav.pull-right')) ); }, edit: function () { @@ -667,23 +674,34 @@ }, 'change input[type=file]': 'file_selection', 'change input.url': 'preview_image', - 'click .existing-attachments a': 'select_existing', + 'click a[href=#existing]': 'browse_existing', + 'change select.image-style': 'preview_image', }), start: function () { var selection = this.editor.getSelection(); var el = selection && selection.getSelectedElement(); this.element = null; + + var $select = this.$('.image-style'); + var $options = $select.children(); + this.image_styles = $options.map(function () { return this.value; }).get(); + if (el && el.is('img')) { this.element = el; + _(this.image_styles).each(function (style) { + if (el.hasClass(style)) { + $select.val(style); + } + }); + // set_image must follow setup of image style this.set_image(el.getAttribute('src')); } - return $.when( - this._super(), - this.fetch_existing().then(this.proxy('fetched_existing'))); + return this._super(); }, save: function () { var url = this.$('input.url').val(); + var style = this.$('.image-style').val(); var element, editor = this.editor; if (!(element = this.element)) { element = editor.document.createElement('img'); @@ -697,7 +715,10 @@ }, 0); } element.setAttribute('src', url); - this._super(); + $(element.$).removeClass(this.image_styles.join(' ')); + if (style) { element.addClass(style); } + + return this._super(); }, /** @@ -735,17 +756,54 @@ var image = this.$('input.url').val(); if (!image) { return; } - this.$('img.image-preview').attr('src', image); + this.$('img.image-preview') + .attr('src', image) + .removeClass(this.image_styles.join(' ')) + .addClass(this.$('select.image-style').val()); + }, + + browse_existing: function (e) { + e.preventDefault(); + new website.editor.ExistingImageDialog(this).appendTo(document.body); + }, + }); + + var IMAGES_PER_ROW = 6; + var IMAGES_ROWS = 4; + website.editor.ExistingImageDialog = website.editor.Dialog.extend({ + template: 'website.editor.dialog.image.existing', + events: _.extend({}, website.editor.Dialog.prototype.events, { + 'click .existing-attachments img': 'select_existing', + 'click .pager > li': function (e) { + e.preventDefault(); + var $target = $(e.currentTarget); + if ($target.hasClass('disabled')) { + return; + } + this.page += $target.hasClass('previous') ? -1 : 1; + this.display_attachments(); + }, + }), + init: function (parent) { + this.image = null; + this.page = 0; + this.parent = parent; + this._super(parent.editor); + }, + + start: function () { + return $.when( + this._super(), + this.fetch_existing().then(this.proxy('fetched_existing'))); }, fetch_existing: function () { - // FIXME: lazy load attachments? return openerp.jsonRpc('/web/dataset/call_kw', 'call', { model: 'ir.attachment', method: 'search_read', args: [], kwargs: { - fields: ['name'], + fields: ['name', 'website_url'], domain: [['res_model', '=', 'ir.ui.view']], order: 'name', context: website.get_context(), @@ -753,17 +811,36 @@ }); }, fetched_existing: function (records) { + this.records = records; + this.display_attachments(); + }, + display_attachments: function () { + var per_screen = IMAGES_PER_ROW * IMAGES_ROWS; + + var from = this.page * per_screen; + var records = this.records; + // Create rows of 3 records var rows = _(records).chain() - .groupBy(function (_, index) { return Math.floor(index / 3); }) + .slice(from, from + per_screen) + .groupBy(function (_, index) { return Math.floor(index / IMAGES_PER_ROW); }) .values() .value(); + this.$('.existing-attachments').replaceWith( - openerp.qweb.render('website.editor.dialog.image.existing', {rows: rows})); + openerp.qweb.render( + 'website.editor.dialog.image.existing.content', {rows: rows})); + this.$('.pager') + .find('li.previous').toggleClass('disabled', (from === 0)).end() + .find('li.next').toggleClass('disabled', (from + per_screen >= records.length)); + }, select_existing: function (e) { - e.preventDefault(); - this.set_image(e.currentTarget.getAttribute('href')); + var link = $(e.currentTarget).attr('src'); + if (link) { + this.parent.set_image(link); + } + this.close() }, }); diff --git a/addons/website/static/src/js/website.mobile.js b/addons/website/static/src/js/website.mobile.js index 6487b2b457b..d4630d0a0c2 100644 --- a/addons/website/static/src/js/website.mobile.js +++ b/addons/website/static/src/js/website.mobile.js @@ -17,7 +17,7 @@ 'hidden.bs.modal': 'destroy' }, start: function () { - document.getElementById("mobile-viewport").src = window.location.href + "?mobile-preview=true"; + document.getElementById("mobile-viewport").src = window.location.origin + window.location.pathname + "#mobile-preview"; this.$el.modal(); }, }); diff --git a/addons/website/static/src/js/website.seo.js b/addons/website/static/src/js/website.seo.js index 738bd46d413..1d9234165c4 100644 --- a/addons/website/static/src/js/website.seo.js +++ b/addons/website/static/src/js/website.seo.js @@ -6,30 +6,52 @@ website.EditorBar.include({ events: _.extend({}, website.EditorBar.prototype.events, { - 'click a[data-action=promote-current-page]': 'promotePage', + 'click a[data-action=promote-current-page]': 'launchSeo', }), - promotePage: function () { + launchSeo: function () { (new website.seo.Configurator()).appendTo($(document.body)); }, }); website.seo = {}; + function analyzeKeyword(htmlPage, keyword) { + return htmlPage.isInTitle(keyword) ? { + title: 'keyword-in-title', + description: "This keyword is used in the page title", + } : htmlPage.isInDescription(keyword) ? { + title: 'keyword-in-description', + description: "This keyword is used in the page description", + } : htmlPage.isInBody(keyword) ? { + title: 'keyword-in-body', + description: "This keyword is used in the page content." + } : { title: "", description: "" }; + } + website.seo.Suggestion = openerp.Widget.extend({ template: 'website.seo_suggestion', events: { 'click .js_seo_suggestion': 'select', }, - init: function (parent, keyword) { - this.keyword = keyword; - var keywordRegex = new RegExp(this.keyword, "gi"); - var pageText = $('body').children().not('.js_seo_configuration').text(); - var isKeywordInBody = keywordRegex.test(pageText); - // cf. http://getbootstrap.com/components/#labels - // default, primary, success, info, warning, danger - this.type = isKeywordInBody ? 'info' : 'default'; + init: function (parent, options) { + this.root = options.root; + this.keyword = options.keyword; + this.htmlPage = options.page; this._super(parent); }, + start: function () { + this.htmlPage.on('title-changed', this, this.renderElement); + this.htmlPage.on('description-changed', this, this.renderElement); + }, + analyze: function () { + return analyzeKeyword(this.htmlPage, this.keyword); + }, + highlight: function () { + return this.analyze().title; + }, + tooltip: function () { + return this.analyze().description; + }, select: function () { this.trigger('selected', this.keyword); }, @@ -37,8 +59,9 @@ website.seo.SuggestionList = openerp.Widget.extend({ template: 'website.seo_list', - init: function (parent, word) { - this.word = word; + init: function (parent, options) { + this.root = options.root; + this.htmlPage = options.page; this._super(parent); }, start: function () { @@ -50,14 +73,18 @@ function addSuggestions (list) { self.$el.empty(); // TODO Improve algorithm + Ajust based on custom user keywords - var nameRegex = new RegExp(self.companyName, "gi"); - var cleanList = _.map(list, function removeCompanyName (word) { - return word.replace(nameRegex, "").trim(); + var regex = new RegExp(self.root, "gi"); + var cleanList = _.map(list, function (word) { + return word.replace(regex, "").trim(); }); // TODO Order properly ? _.each(_.uniq(cleanList), function (keyword) { if (keyword) { - var suggestion = new website.seo.Suggestion(self, keyword); + var suggestion = new website.seo.Suggestion(self, { + root: self.root, + keyword: keyword, + page: self.htmlPage, + }); suggestion.on('selected', self, function (word) { self.trigger('selected', word); }); @@ -65,7 +92,7 @@ } }); } - $.getJSON("http://seo.eu01.aws.af.cm/suggest/"+encodeURIComponent(this.word + " "), addSuggestions); + $.getJSON("http://seo.eu01.aws.af.cm/suggest/"+encodeURIComponent(this.root + " "), addSuggestions); }, }); @@ -75,21 +102,37 @@ 'click a[data-action=remove-keyword]': 'destroy', }, maxWordsPerKeyword: 4, // TODO Check - init: function (parent, keyword) { - this.keyword = keyword; - // cf. http://getbootstrap.com/components/#labels - // default, primary, success, info, warning, danger - this.type = 'warning'; + init: function (parent, options) { + this.keyword = options.word; + this.htmlPage = options.page; this._super(parent); }, start: function () { - var self = this; - self.suggestionList = new website.seo.SuggestionList(self, this.keyword); - self.suggestionList.on('selected', self, function (word) { - self.trigger('selected', word); + this.htmlPage.on('title-changed', this, this.updateLabel); + this.htmlPage.on('description-changed', this, this.updateLabel); + this.suggestionList = new website.seo.SuggestionList(this, { + root: this.keyword, + page: this.htmlPage, + }); + this.suggestionList.on('selected', this, function (word) { + this.trigger('selected', word); }); this.suggestionList.appendTo(this.$('.js_seo_keyword_suggestion')); }, + analyze: function () { + return analyzeKeyword(this.htmlPage, this.keyword); + }, + highlight: function () { + return this.analyze().title; + }, + tooltip: function () { + return this.analyze().description; + }, + updateLabel: function () { + var cssClass = "oe_seo_keyword js_seo_keyword " + this.highlight(); + this.$(".js_seo_keyword").attr('class', cssClass); + this.$(".js_seo_keyword").attr('title', this.tooltip()); + }, destroy: function () { this.trigger('removed'); this._super(); @@ -99,28 +142,44 @@ website.seo.KeywordList = openerp.Widget.extend({ template: 'website.seo_list', maxKeywords: 10, - init: function (parent) { + init: function (parent, options) { + this.htmlPage = options.page; this._super(parent); }, + start: function () { + var self = this; + var existingKeywords = self.htmlPage.keywords(); + if (existingKeywords.length > 0) { + _.each(existingKeywords, function (word) { + self.add.call(self, word); + }); + } else { + var companyName = self.htmlPage.company().toLowerCase(); + self.add(companyName); + } + }, keywords: function () { var result = []; - this.$('span.js_seo_keyword').each(function () { + this.$('.js_seo_keyword').each(function () { result.push($(this).data('keyword')); }); return result; }, - isKeywordListFull: function () { + isFull: function () { return this.keywords().length >= this.maxKeywords; }, - isExistingKeyword: function (word) { + exists: function (word) { return _.contains(this.keywords(), word); }, add: function (candidate) { var self = this; // TODO Refine - var word = candidate ? candidate.replace(/[,;.:<>]+/g, " ").replace(/ +/g, " ").trim() : ""; - if (word && !self.isKeywordListFull() && !self.isExistingKeyword(word)) { - var keyword = new website.seo.Keyword(self, word); + var word = candidate ? candidate.replace(/[,;.:<>]+/g, " ").replace(/ +/g, " ").trim().toLowerCase() : ""; + if (word && !self.isFull() && !self.exists(word)) { + var keyword = new website.seo.Keyword(self, { + word: word, + page: this.htmlPage, + }); keyword.on('removed', self, function () { self.trigger('list-not-full'); self.trigger('removed', word); @@ -130,7 +189,7 @@ }); keyword.appendTo(self.$el); } - if (self.isKeywordListFull()) { + if (self.isFull()) { self.trigger('list-full'); } }, @@ -147,9 +206,13 @@ website.seo.ImageList = openerp.Widget.extend({ + init: function (parent, options) { + this.htmlPage = options.page; + this._super(parent); + }, start: function () { var self = this; - new website.seo.HtmlPage().images().each(function (index, image) { + this.htmlPage.images().each(function (index, image) { new website.seo.Image(self, image).appendTo(self.$el); }); }, @@ -169,29 +232,33 @@ }, }); - website.seo.HtmlPage = openerp.Class.extend({ + website.seo.HtmlPage = openerp.Class.extend(openerp.PropertiesMixin, { url: function () { var url = window.location.href; var hashIndex = url.indexOf('#'); return hashIndex >= 0 ? url.substring(0, hashIndex) : url; }, title: function () { - return $('title').text(); + return $('title').text().trim(); }, changeTitle: function (title) { $('title').text(title); + this.trigger('title-changed', title); }, description: function () { - return $('meta[name=description]').attr('value'); + return $('meta[name=description]').attr('value').trim(); }, changeDescription: function (description) { - return $('meta[name=description]').attr('value', description); + $('meta[name=description]').attr('value', description); + this.trigger('description-changed', description); }, keywords: function () { - return $('meta[name=keywords]').attr('value').split(","); + var parsed = $('meta[name=keywords]').attr('value').split(","); + return parsed[0] ? parsed: []; }, changeKeywords: function (keywords) { - return $('meta[name=keywords]').attr('value', keyword.join(",")); + $('meta[name=keywords]').attr('value', keywords.join(",")); + this.trigger('keywords-changed', keywords); }, headers: function (tag) { return $('#wrap '+tag).map(function () { @@ -210,6 +277,18 @@ company: function () { return $('meta[name="openerp.company"]').attr('value'); }, + bodyText: function () { + return $('body').children().not('.js_seo_configuration').text(); + }, + isInBody: function (text) { + return new RegExp(text, "gi").test(this.bodyText()); + }, + isInTitle: function (text) { + return new RegExp(text, "gi").test(this.title()); + }, + isInDescription: function (text) { + return new RegExp(text, "gi").test(this.description()); + }, }); website.seo.Tip = openerp.Widget.extend({ @@ -245,10 +324,14 @@ $modal.find('.js_seo_page_url').text(htmlPage.url()); $modal.find('input[name=seo_page_title]').val(htmlPage.title()); $modal.find('textarea[name=seo_page_description]').val(htmlPage.description()); - self.suggestImprovements(htmlPage); - self.imageList = new website.seo.ImageList(self); - self.imageList.appendTo($modal.find('.js_seo_image_list')); - self.keywordList = new website.seo.KeywordList(self); + self.suggestImprovements(); + self.imageList = new website.seo.ImageList(self, { page: htmlPage }); + if (htmlPage.images().length === 0) { + $modal.find('.js_image_section').remove() + } else { + self.imageList.appendTo($modal.find('.js_seo_image_list')); + } + self.keywordList = new website.seo.KeywordList(self, { page: htmlPage }); self.keywordList.on('list-full', self, function () { $modal.find('input[name=seo_page_keywords]') .attr('readonly', "readonly") @@ -266,11 +349,9 @@ self.keywordList.add(word); }); self.keywordList.appendTo($modal.find('.js_seo_keywords_list')); - var companyName = htmlPage.company().toLowerCase(); - self.addKeyword(companyName); $modal.modal(); }, - suggestImprovements: function (parser) { + suggestImprovements: function () { var tips = []; var self = this; function displayTip(message, type) { @@ -279,17 +360,17 @@ type: type, }).appendTo(self.$('.js_seo_tips')); } - var htmlPage = parser || new website.seo.HtmlPage(); + var htmlPage = this.htmlPage; if (htmlPage.headers('h1').length === 0) { tips.push({ type: 'warning', - message: "You don't have an <h1> tag on your page.", + message: "This page seems to be missing an <h1> tag.", }); } if (htmlPage.headers('h1').length > 1) { tips.push({ type: 'warning', - message: "You have more than one <h1> tag on your page.", + message: "The page contains more than one <h1> tag.", }); } if (tips.length > 0) { @@ -297,7 +378,7 @@ displayTip(tip.message, tip.type); }); } else { - displayTip("Your page makup is appropriate for search engines.", 'success'); + displayTip("The markup on this page is appropriate for search engines.", 'success'); } }, confirmKeyword: function (e) { @@ -327,7 +408,7 @@ setTimeout(function () { var title = self.$('input[name=seo_page_title]').val(); self.htmlPage.changeTitle(title); - }, 1); + }, 0); }, descriptionChanged: function () { var self = this; @@ -336,5 +417,9 @@ self.htmlPage.changeDescription(description); }, 1); }, + destroy: function () { + this.htmlPage.changeKeywords(this.keywordList.keywords()); + this._super(); + }, }); })(); diff --git a/addons/website/static/src/js/website.snippets.js b/addons/website/static/src/js/website.snippets.js index 36e72fcff60..3457fbb66e2 100644 --- a/addons/website/static/src/js/website.snippets.js +++ b/addons/website/static/src/js/website.snippets.js @@ -5,54 +5,70 @@ website.templates.push('/website/static/src/xml/website.snippets.xml'); website.EditorBar.include({ - events: _.extend({}, website.EditorBar.prototype.events, { - 'click button[data-action=snippet]': 'snippet', - }), start: function () { - return this._super().then(function () { - - this.$buttons.snippet = this.$('button[data-action=snippet]'); - - }.bind(this)); + var self = this; + $("[data-oe-model]").on('click', function (event) { + var tag = event.srcElement.tagName.toLowerCase(); + var $this = $(event.srcElement); + if (!(tag === 'a' || tag === "button") && !$this.parents("a, button").length) { + self.$('[data-action="edit"]').parent().effect('bounce', {distance: 18, times: 5}, 250); + } + }); + return this._super(); }, edit: function () { - window.snippets = this.snippets = new website.snippet.BuildingBlock(this); - this.snippets.appendTo($(document.body)); + $("body").off('click'); + var self = this; + self.on('rte:ready', this, function () { + + window.snippets = self.snippets = new website.snippet.BuildingBlock(this); + self.snippets.appendTo(self.$el); + + }); return this._super.apply(this, arguments); }, - snippet: function (ev) { - this.snippets.toggle(); - }, save: function () { - $('body').trigger("save"); + remove_added_snippet_id(); this._super(); }, }); + + $(document).ready(function () { + hack_to_add_snippet_id(); + $("[data-snippet-id]").each(function() { + var $snipped_id = $(this); + if (typeof $snipped_id.data("snippet-view") === 'undefined' && + website.snippet.animationRegistry[$snipped_id.data("snippet-id")]) { + $snipped_id.data("snippet-view", new website.snippet.animationRegistry[$snipped_id.data("snippet-id")]($snipped_id)); + } + }); + }); + /* ----- SNIPPET SELECTOR ---- */ website.snippet = {}; + // puts $el at the same absolute position as $target - website.snippet.cover_target = function ($el, $target){ - $el.css({ - 'position': 'absolute', - 'width': $target.outerWidth(), - 'height': $target.outerHeight(), - }); - $el.css($target.offset()); - }; function hack_to_add_snippet_id () { _.each(website.snippet.selector, function (val) { $(val[0]).each(function() { - if ($(this).is("[data-snippet-id='"+ val[1]+"']")) - $(this).removeAttr("data-snippet-id"); - if (!$(this).is("[data-snippet-id]") && $(this).parents("[data-oe-model]").length) + if (!$(this).is("[data-snippet-id]") && $(this).parents("[data-oe-model]").length) { $(this).attr("data-snippet-id", val[1]); + } + }); + }); + } + function remove_added_snippet_id () { + _.each(website.snippet.selector, function (val) { + $(val[0]).each(function() { + if ($(this).data("snippet-id") === val[1]) { + $(this).removeAttr("data-snippet-id"); + } }); }); } - website.snippet.selector = []; website.snippet.BuildingBlock = openerp.Widget.extend({ @@ -65,49 +81,134 @@ $("<div id='oe_manipulators'></div>").appendTo('body'); } this.$active_snipped_id = false; - this.active = false; - this.parent_of_editable_box = "body > :not(:has(#website-top-view)):not(#oe_manipulators):not(#oe_snippets) "; hack_to_add_snippet_id(); + $("body").on('DOMNodeInserted', hack_to_add_snippet_id); + }, + dom_filter: function (dom) { + if (typeof dom === "string") { + var include = "[data-oe-model]"; + var sdom = dom.split(','); + dom = ""; + _.each(sdom, function (val) { + val = val.replace(/^\s+|\s+$/g, ''); + dom += "body " + include + " " + val + ", "; + val = val.split(" "); + dom += "body "+ val.shift() + include + val.join(" ") + ", "; + }); + dom = dom.replace(/,\s*$/g, ''); + return $(dom); + } else { + return $(dom).is("[data-oe-model]") || $(dom).parents("[data-oe-model]").length ? $(dom) : $(""); + } }, start: function() { var self = this; - var snippets_template = []; + var $ul = this.parent.$("#website-top-edit ul"); + + var $button = $(openerp.qweb.render('website.snippets_button')) + .click(function () {self.$el.toggleClass("hidden");}) + .prependTo($ul); + + this.fetch_snippet_templates(); + + this.bind_selected_manipulator(); + this.bind_snippet_click_editor(); + this.activate_overlay_zones(); + + this.scrollspy(); + this.$el.addClass("hidden"); + + this.$modal = $(openerp.qweb.render('website.snippets_modal')); + this.$modal.appendTo("body"); + }, + fetch_snippet_templates: function () { + var self = this; + this.style_templates = {}; + _.each(openerp.qweb.compiled_templates, function (val, key) { if (key.indexOf('website.snippets.') === 0) { var $snippet = $(openerp.qweb.render(key)).addClass("oe_snippet"); - if ($snippet.data("action")) { - self.$el.find('#snippet_' + $snippet.data('category')).append($snippet); - self.make_snippet_draggable($snippet); + var snipped_id = $snippet.data("snippet-id"); + if (snipped_id) { + + if ($snippet.data('category') === 'style') { + self.style_templates[snipped_id] = { + 'snipped-id' : snipped_id, + 'selector': $snippet.data('selector'), + 'class': $snippet.find(".oe_snippet_class").text(), + 'label': $snippet.find(".oe_snippet_label").text(), + '$el': $snippet + }; + } + if ($snippet.find(".oe_snippet_thumbnail").length) { + self.$el.find('#snippet_' + $snippet.data('category')).append($snippet); + self.make_snippet_draggable($snippet); + } } } }); + }, + scrollspy: function (){ + var self = this; + var $ul = this.$("ul"); + var $pill = self.$(".pill-content"); + var padding = parseInt($pill.css("padding-left")); + var $scroll = this.$(".scroll"); + + $scroll.scroll(function () { + $pill.find("> div").each(function () { + if ($(this).position().left <= padding) { + $ul.find("> li").removeClass('active'); + $ul.find("a[href='#" + $(this).attr("id") + "']").parent("li").addClass('active'); + } + }); + }); - this.bind_selected_manipulator(); - this.bind_snippet_click_editor(); + $ul.find("a").click(function (event) { + event.preventDefault(); + $scroll.scrollLeft( $scroll.scrollLeft() + $($(event.currentTarget).attr("href")).position().left - padding ); + return false; + }); + + $pill.css("padding-right", self.$el.outerWidth() - padding + 10 - $pill.find("> div:last").outerWidth()); + $ul.find("> li:first").addClass('active'); + }, + cover_target: function ($el, $target){ + var pos = $target.offset(); + var mt = parseInt($target.css("margin-top") || 0); + var mb = parseInt($target.css("margin-bottom") || 0); + $el.css({ + 'position': 'absolute', + 'width': $target.outerWidth(), + 'height': $target.outerHeight() + mt + mb, + 'top': pos.top - mt, + 'left': pos.left + }); + }, + show: function () { + this.$el.removeClass("hidden"); + }, + hide: function () { + this.$el.addClass("hidden"); }, bind_snippet_click_editor: function () { var self = this; var snipped_event_flag = false; $("body").on('click', "[data-snippet-id]", function (event) { - if (!self.active || snipped_event_flag) { + if (snipped_event_flag) { return; } - var $target = $(event.currentTarget); - if (self.$active_snipped_id) { - if (self.$active_snipped_id[0] === $target[0] || $.contains(self.$active_snipped_id, $target[0])) { - var $parent = self.$active_snipped_id.parents("[data-snippet-id]:first"); - if ($parent.length) { - $target = $parent; - } - } - } snipped_event_flag = true; setTimeout(function () {snipped_event_flag = false;}, 0); + var $target = $(event.currentTarget); + if (self.$active_snipped_id && self.$active_snipped_id.is($target)) { + return; + } self.make_active($target); }); - $("body > :not(:has(#website-top-view)):not(#oe_manipulators)").on('click', function (ev) { + $("[data-oe-model]").on('click', function (ev) { if (!snipped_event_flag && self.$active_snipped_id && !self.$active_snipped_id.parents("[data-snippet-id]:first")) { self.make_active(false); } @@ -151,10 +252,10 @@ create_overlay: function ($snipped_id) { if (typeof $snipped_id.data("snippet-editor") === 'undefined') { this.activate_overlay_zones($snipped_id); - var editor = website.snippet.editorRegistry[$snipped_id.data("snippet-id")] || website.snippet.Editor; + var editor = website.snippet.editorRegistry[$snipped_id.data("snippet-id")] || website.snippet.editorRegistry.resize; $snipped_id.data("snippet-editor", new editor(this, $snipped_id)); } - website.snippet.cover_target($snipped_id.data('overlay'), $snipped_id); + this.cover_target($snipped_id.data('overlay'), $snipped_id); }, path_eval: function(path){ @@ -170,21 +271,19 @@ var self = this; var $selected_target = null; $("body").mouseover(function (event){ - if (!self.active) { - return; - } var $target = $(event.srcElement).parents("[data-snippet-id]:first"); + $target = self.dom_filter($target); if($target.length && !self.editor_busy) { if($selected_target != $target){ - if($selected_target){ - $selected_target.data('overlay').removeClass('oe_selected'); + if($selected_target && $selected_target.data('overlay')){ + $selected_target.data('overlay').removeClass('oe_hover'); } $selected_target = $target; self.create_overlay($target); - $target.data('overlay').addClass('oe_selected'); + $target.data('overlay').addClass('oe_hover'); } - } else if($selected_target) { - $selected_target.data('overlay').removeClass('oe_selected'); + } else if($selected_target && $selected_target.data('overlay')) { + $selected_target.data('overlay').removeClass('oe_hover'); } }); }, @@ -192,22 +291,47 @@ // activate drag and drop for the snippets in the snippet toolbar make_snippet_draggable: function($snippet){ var self = this; + var $toInsert = false; + var $tumb = $snippet.find(".oe_snippet_thumbnail"); + var dropped = false; $snippet.draggable({ + greedy: true, helper: 'clone', zIndex: '1000', appendTo: 'body', cursor: "move", + handle: ".oe_snippet_thumbnail", + cursorAt: { + 'left': $tumb.outerWidth()/2, + 'top': $tumb.outerHeight()/2 + }, start: function(){ - var action = $snippet.data('action'); + self.hide(); + dropped = false; + var snipped_id = $snippet.data('snippet-id'); + var action = $snippet.find('.oe_snippet_body').size() ? 'insert' : 'mutate'; if( action === 'insert'){ + if (!$snippet.data('selector-siblings') && !$snippet.data('selector-children') && !$snippet.data('selector-vertical-children')) { + console.debug($snippet.data("snippet-id") + " have oe_snippet_body class and have not for insert action"+ + "data-selector-siblings, data-selector-children or data-selector-vertical-children tag for mutate action"); + return; + } self.activate_insertion_zones({ siblings: $snippet.data('selector-siblings'), - childs: $snippet.data('selector-childs'), - vertical_childs: $snippet.data('selector-vertical-childs') + children: $snippet.data('selector-children'), + vertical_children: $snippet.data('selector-vertical-children') }); - } else if( action === 'mutate' ){ + $toInsert = $snippet.find('.oe_snippet_body').clone(); + $toInsert.removeClass('oe_snippet_body'); + $toInsert.attr('data-snippet-id', snipped_id); + + } else if( action === 'mutate' ){ + if (!$snippet.data('selector')) { + console.debug($snippet.data("snippet-id") + " have not oe_snippet_body class and have not data-selector tag"); + return; + } var $targets = self.activate_overlay_zones($snippet.data('selector')); $targets.each(function(){ var $clone = $(this).data('overlay').clone(); @@ -219,49 +343,52 @@ $('.oe_drop_zone').droppable({ over: function(){ - // FIXME: stupid hack to prevent multiple droppable to activate at once ... - // it's not even working properly but it's better than nothing. - $(".oe_drop_zone.oe_hover").removeClass("oe_hover"); - $(this).addClass("oe_hover"); + if( action === 'insert'){ + dropped = true; + $(this).first().after($toInsert); + } }, out: function(){ - $(this).removeClass("oe_hover"); + if( action === 'insert'){ + dropped = false; + $toInsert.detach(); + } }, drop: function(){ - var snipped_id = $snippet.data('snippet-id'); - - if (!$(".oe_drop_zone.oe_hover").length) { - return false; - } + dropped = true; var $target = false; - if($snippet.find('.oe_snippet_body').size()){ - var $toInsert = $snippet.find('.oe_snippet_body').clone(); - $toInsert.removeClass('oe_snippet_body'); - $toInsert.attr('data-snippet-id', snipped_id); - $(".oe_drop_zone.oe_hover").first().after($toInsert); + if(action === 'insert'){ $target = $toInsert; - hack_to_add_snippet_id(); - } else { - $target = $(".oe_drop_zone.oe_hover").first().data('target'); - } - - $('.oe_drop_zone').droppable('destroy').remove(); - if (website.snippet.animationRegistry[snipped_id]) { - new website.snippet.animationRegistry[snipped_id]($target); - } - if (website.snippet.editorRegistry[snipped_id]) { + if (website.snippet.animationRegistry[snipped_id]) { + new website.snippet.animationRegistry[snipped_id]($target); + } + self.create_overlay($target); $target.data("snippet-editor").build_snippet($target); - setTimeout(function () {self.make_active($target);},0); + + } else { + $target = $(this).data('target'); + + self.create_overlay($target); + if (website.snippet.editorRegistry[snipped_id]) { + var snippet = new website.snippet.editorRegistry[snipped_id](self, $target); + snippet.build_snippet($target); + } } + $('.oe_drop_zone').remove(); + + setTimeout(function () {self.make_active($target);},0); }, }); }, stop: function(){ $('.oe_drop_zone').droppable('destroy').remove(); + if (!dropped) { + self.$modal.modal('toggle'); + } }, }); }, @@ -272,46 +399,22 @@ return $(this).data('snippet-id') === id; }).first(); }, - // WIP - make_draggable_instance: function($instance){ - var self = this; - var $snippet = get_snippet_from_id($instance.data('snippet-id')); - - $instance.draggable({ - greedy: true, - helper: 'clone', - zIndex: '1000', - appendTo: 'body', - start: function(){ - var action = $snippet.data('action'); - if(action === 'insert'){ - - self.activate_insertion_zones({ - siblings: $snippet.data('selector-siblings'), - child: $snippet.data('selector-childs'), - vertical_childs: $snippet.data('selector-vertical-childs') - }); - - } - } - }); - }, // Create element insertion drop zones. two css selectors can be provided - // selector.childs -> will insert drop zones as direct child of the selected elements + // selector.children -> will insert drop zones as direct child of the selected elements // in case the selected elements have children themselves, dropzones will be interleaved // with them. // selector.siblings -> will insert drop zones after and before selected elements activate_insertion_zones: function(selector){ var self = this; - var child_selector = selector.childs ? this.parent_of_editable_box + (selector.childs).split(",").join(this.parent_of_editable_box) : false; - var sibling_selector = selector.siblings ? this.parent_of_editable_box + (selector.siblings).split(",").join(this.parent_of_editable_box) : false; - var vertical_child_selector = selector.vertical_childs ? this.parent_of_editable_box + (selector.vertical_childs).split(",").join(this.parent_of_editable_box) : false; + var child_selector = selector.children; + var sibling_selector = selector.siblings; + var vertical_child_selector = selector.vertical_children; var zone_template = "<div class='oe_drop_zone oe_insert'></div>"; if(child_selector){ - $(child_selector).each(function (){ + self.dom_filter(child_selector).each(function (){ var $zone = $(this); $zone.find('> *:not(.oe_drop_zone):visible').after(zone_template); $zone.prepend(zone_template); @@ -319,16 +422,38 @@ } if(vertical_child_selector){ - $(vertical_child_selector).each(function (){ + self.dom_filter(vertical_child_selector).each(function (){ var $zone = $(this); - var $template = $(zone_template).addClass("oe_vertical").css('height', $zone.outerHeight()+'px'); - $zone.find('> *:not(.oe_drop_zone):visible').after($template); - $zone.prepend($template.clone()); + var $template = $(zone_template).addClass("oe_vertical"); + var nb = 0; + var $lastinsert = false; + var left = 0; + var temp_left = 0; + $zone.find('> *:not(.oe_drop_zone):visible').each(function () { + var $col = $(this); + $template.css('height', ($col.outerHeight() + parseInt($col.css("margin-top")) + parseInt($col.css("margin-bottom")))+'px'); + $lastinsert = $template.clone(); + $(this).after($lastinsert); + + temp_left = $col.position().left; + if (left === temp_left) { + $col.prev(".oe_drop_zone.oe_vertical").remove(); + $col.before($template.clone().css("clear", "left")); + } + else if (!nb) { + $col.before($template.clone()); + } + left = temp_left; + nb ++; + }); + if (!nb) { + $zone.prepend($template.css('height', $zone.outerHeight()+'px')); + } }); } if(sibling_selector){ - $(sibling_selector).each(function (){ + self.dom_filter(sibling_selector).each(function (){ var $zone = $(this); if($zone.prev('.oe_drop_zone:visible').length === 0){ $zone.before(zone_template); @@ -342,11 +467,11 @@ var count; do { count = 0; - var $zones = $('.oe_drop_zone + .oe_drop_zone'); // no two consecutive zones - count += $zones.length; - $zones.remove(); + // var $zones = $('.oe_drop_zone + .oe_drop_zone'); // no two consecutive zones + // count += $zones.length; + // $zones.remove(); - $zones = $('.oe_drop_zone > .oe_drop_zone').remove(); // no recusrive zones + $zones = $('.oe_drop_zone > .oe_drop_zone:not(.oe_vertical)').remove(); // no recusrive zones count += $zones.length; $zones.remove(); } while (count > 0); @@ -377,11 +502,8 @@ // generate drop zones covering the elements selected by the selector // we generate overlay drop zones only to get an idea of where the snippet are, the drop activate_overlay_zones: function(selector){ - selector = selector || '[data-snippet-id]'; - if (typeof selector === 'string') - selector = this.parent_of_editable_box + selector.split(",").join(this.parent_of_editable_box); - - var $targets = $(selector); + var $targets = this.dom_filter(selector || '[data-snippet-id]'); + var self = this; function is_visible($el){ return $el.css('display') != 'none' @@ -407,23 +529,16 @@ $target.data('overlay',$zone); $target.on("DOMNodeInserted DOMNodeRemoved DOMSubtreeModified", function () { - website.snippet.cover_target($zone, $target); + self.cover_target($zone, $target); + }); + $('body').on("resize", function () { + self.cover_target($zone, $target); }); } - website.snippet.cover_target($target.data('overlay'), $target); + self.cover_target($target.data('overlay'), $target); }); return $targets; - }, - - toggle: function(){ - this.active = !this.active; - if(this.active){ - this.$el.removeClass('hide'); - this.activate_overlay_zones(); - } else { - this.$el.addClass('hide'); - } - }, + } }); @@ -434,6 +549,13 @@ }, init: function (dom) { this.$el = this.$target = $(dom); + this.start(); + }, + /* + * start + * This method is called after init + */ + start: function () { }, /* onFocusEdit * if they are an editor for this snippet-id @@ -456,17 +578,6 @@ }, }); - $(document).ready(function () { - hack_to_add_snippet_id(); - $("[data-snippet-id]").each(function() { - var $snipped_id = $(this); - if (typeof $snipped_id.data("snippet-view") === 'undefined' && - website.snippet.animationRegistry[$snipped_id.data("snippet-id")]) { - $snipped_id.data("snippet-view", new website.snippet.animationRegistry[$snipped_id.data("snippet-id")]($snipped_id)); - } - }); - }); - website.snippet.editorRegistry = {}; website.snippet.Editor = openerp.Class.extend({ @@ -474,7 +585,10 @@ this.parent = parent; this.$target = $(dom); this.$overlay = this.$target.data('overlay'); + this.snippet_id = this.$target.data("snippet-id"); this._readXMLData(); + this.load_style_options(); + this.get_parent_block(); this.start(); }, @@ -496,15 +610,15 @@ * Insert into the view when the thumbnail is drag and droped into a drop zone */ _readXMLData: function() { - if (this.template) { - this.$el = $(openerp.qweb.render(this.template, {widget: this}).trim()); - this.$editor = this.$el.find(".oe_snippet_options"); - this.$thumbnail = this.$el.find(".oe_snippet_thumbnail"); - this.$body = this.$el.find(".oe_snippet_body"); - - var $options = this.$overlay.find(".oe_overlay_options"); - this.$editor.prependTo($options.find(".oe_options ul")); - $options.find(".oe_label").text(this.$el.find('.oe_snippet_thumbnail.oe_label, .oe_snippet_thumbnail .oe_label').text()); + this.$el = $(openerp.qweb.render("website.snippets." + this.snippet_id, {widget: this}).trim()); + this.$editor = this.$el.find(".oe_snippet_options"); + this.$thumbnail = this.$el.find(".oe_snippet_thumbnail"); + this.$body = this.$el.find(".oe_snippet_body"); + + var $options = this.$overlay.find(".oe_overlay_options"); + this.$editor.prependTo($options.find(".oe_options ul")); + if ($options.find(".oe_options ul li").length) { + $options.find(".oe_options").removeClass("hidden"); } }, @@ -512,41 +626,127 @@ // activate drag and drop for the snippets in the snippet toolbar _drag_and_drop: function(){ var self = this; + var dropped = false; + var $move = this.$overlay.find(".oe_snippet_move"); this.$overlay.draggable({ greedy: true, appendTo: 'body', cursor: "move", + handle: ".oe_snippet_move", cursorAt: { - top: self.$target.outerHeight()/2, - left: self.$target.outerWidth()/2 }, - distance: 20, - handle: ".js_box_move", + left: 18, + top: 14 + }, + helper: function() { + var $clone = $(this).clone().css({width: "24px", height: "24px", border: 0}); + $clone.find(".oe_overlay_options >:not(.oe_snippet_move), .oe_handle").remove(); + $clone.find(":not(.glyphicon)").css({position: 'absolute', top: 0, left: 0}); + return $clone.appendTo("body").removeClass("hidden"); + }, start: function(){ + self.parent.hide(); self.parent.editor_busy = true; - self.$target.css("display", "none"); + self.$target.after("<div class='oe_drop_clone' style='display: none;'/>"); + self.$target.detach(); + self.$overlay.addClass("hidden"); self.parent.activate_insertion_zones({ siblings: self.$el ? self.$el.data('selector-siblings') : false, - childs: self.$el ? self.$el.data('selector-childs') : false, - vertical_childs: self.$el ? self.$el.data('selector-vertical-childs') : false, + children: self.$el ? self.$el.data('selector-children') : false, + vertical_children: self.$el ? self.$el.data('selector-vertical-children') : false, }); $("body").addClass('move-important'); $('.oe_drop_zone').droppable({ - hoverClass: "oe_hover", - drop: function(){ - $(this).after(self.$target); + over: function(){ + $(".oe_drop_zone.hide").removeClass("hide"); + $(this).addClass("hide").first().after(self.$target); + dropped = true; + }, + out: function(){ + $(this).removeClass("hide"); + self.$target.detach(); + dropped = false; }, }); }, stop: function(){ + if (!dropped) { + $(".oe_drop_clone").after(self.$target); + } + self.$overlay.removeClass("hidden"); $("body").removeClass('move-important'); $('.oe_drop_zone').droppable('destroy').remove(); - self.$target.css("display", ""); + $(".oe_drop_clone").remove(); self.parent.editor_busy = false; + self.get_parent_block(); setTimeout(function () {self.parent.create_overlay(self.$target);},0); }, }); }, + _clone: function () { + var self = this; + this.$overlay.on('click', '.oe_snippet_clone', function () { + var $clone = self.$target.clone(false); + self.$target.after($clone); + setTimeout(function () { + self.parent.create_overlay($clone); + self.parent.make_active($clone); + },0); + }); + }, + + load_style_options: function () { + var self = this; + var $styles = this.$overlay.find('.oe_options'); + var $ul = $styles.find('ul'); + _.each(this.parent.style_templates, function (val, key) { + if (!self.parent.dom_filter(val.selector).is(self.$target)) { + return; + } + var $li = $("<li class='oe_style'/>").data(val); + $li.append($('<a/>').text(val.label)); + $ul.append($li); + if (self.$target.hasClass( "oe_snippet_" + $li.data("snipped-id") )) { + $li.addClass("active"); + } + $styles.removeClass("hidden"); + }); + $styles.on('click', 'li.oe_style a', _.bind(this.change_style, this)); + }, + change_style: function (event) { + var $li = $(event.currentTarget).parent(); + var snipped_id = $li.data("snipped-id"); + var active = $li.hasClass("active"); + + if (website.snippet.editorRegistry[snipped_id]) { + var snippet = new website.snippet.editorRegistry[snipped_id](this, this.$target); + snippet.build_snippet(this.$target); + } + var _class = "oe_snippet_" + snipped_id + " " + ($li.data("class") || ""); + if (active) { + this.$target.removeClass(_class); + } else { + this.$target.addClass(_class); + } + $li.toggleClass("active"); + }, + + get_parent_block: function () { + var self = this; + var $button = this.$overlay.find('.oe_snippet_parent'); + var $parent = this.$target.parents("[data-snippet-id]:first"); + if ($parent.length) { + $button.removeClass("hidden"); + $button.off("click").on('click', function (event) { + event.preventDefault(); + setTimeout(function () { + self.parent.make_active($parent); + }, 0); + }); + } else { + $button.addClass("hidden"); + } + }, /* * start @@ -554,13 +754,14 @@ */ start: function () { var self = this; - this.$overlay.on('click', '.js_box_remove', function () { + this.$overlay.on('click', '.oe_snippet_remove', function () { self.$target.detach(); self.onBlur(); self.$target.remove(); return false; }); this._drag_and_drop(); + this._clone(); }, /* @@ -603,7 +804,6 @@ website.snippet.editorRegistry.resize = website.snippet.Editor.extend({ - template : "website.snippets.resize", start: function () { var self = this; this._super(); @@ -657,11 +857,10 @@ var xy = event['page'+XY]; var begin = current; var beginClass = self.$target.attr("class"); - var regClass = new RegExp("\\s*" + resize[0][begin].replace(/[-]*[0-9]+/, '[0-9-]+'), 'g'); + var regClass = new RegExp("\\s*" + resize[0][begin].replace(/[-]*[0-9]+/, '[-]*[0-9]+'), 'g'); var cursor = $handle.css("cursor")+'-important'; $("body").addClass(cursor); - self.$overlay.addClass('oe_hover'); var body_mousemove = function (event){ event.preventDefault(); @@ -685,7 +884,7 @@ if (change) { self.on_resize(compass, beginClass, current); - website.snippet.cover_target(self.$overlay, self.$target); + self.parent.cover_target(self.$overlay, self.$target); } }; $('body').mousemove(body_mousemove); @@ -720,7 +919,6 @@ }); website.snippet.editorRegistry.colmd = website.snippet.editorRegistry.resize.extend({ - template : "website.snippets.colmd", getSize: function () { this.grid = this._super(); var width = this.$target.parents(".row:first").first().outerWidth(); @@ -729,7 +927,7 @@ this.grid.e = [_.map(grid, function (v) {return 'col-md-'+v;}), _.map(grid, function (v) {return width/12*v;})]; var grid = [-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11]; - this.grid.w = [_.map(grid, function (v) {return 'col-lg-offset-'+v;}), _.map(grid, function (v) {return width/12*v;}), 12]; + this.grid.w = [_.map(grid, function (v) {return 'col-md-offset-'+v;}), _.map(grid, function (v) {return width/12*v;}), 12]; return this.grid; }, @@ -739,23 +937,26 @@ // don't change the rigth border position when we change the offset (replace col size) var beginCol = Number(beginClass.match(/col-md-([0-9]+)|$/)[1] || 0); - var beginOffset = Number(beginClass.match(/col-lg-offset-([0-9-]+)|$/)[1] || 0); - var offset = Number(this.grid.w[0][current].match(/col-lg-offset-([0-9-]+)|$/)[1] || 0); - - this.$target.attr("class",this.$target.attr("class").replace(/\s*(col-lg-offset-|col-md-)([0-9-]+)/g, '')); - + var beginOffset = Number(beginClass.match(/col-md-offset-([0-9-]+)|$/)[1] || beginClass.match(/col-lg-offset-([0-9-]+)|$/)[1] || 0); + var offset = Number(this.grid.w[0][current].match(/col-md-offset-([0-9-]+)|$/)[1] || 0); + if (offset < 0) { + offset = 0; + } var colSize = beginCol - (offset - beginOffset); + if (colSize <= 0) { + colSize = 1; + offset = beginOffset + beginCol - 1; + } + this.$target.attr("class",this.$target.attr("class").replace(/\s*(col-lg-offset-|col-md-offset-|col-md-)([0-9-]+)/g, '')); + this.$target.addClass('col-md-' + (colSize > 12 ? 12 : colSize)); if (offset > 0) { - this.$target.addClass('col-lg-offset-' + offset); + this.$target.addClass('col-md-offset-' + offset); } }, }); - website.snippet.selector.push([ _.map([1,2,3,4,5,6,7,8,9,10,11,12], function (v) {return '.row > .col-md-'+v;}).join(","), 'colmd']); - website.snippet.editorRegistry.carousel = website.snippet.editorRegistry.resize.extend({ - template : "website.snippets.carousel", build_snippet: function($target) { var id = "myCarousel" + $("body .carousel").size(); $target.attr("id", id); @@ -763,14 +964,34 @@ }, start : function () { this._super(); - var self = this; - this.$editor.find(".js_add").on('click', this.on_add); - this.$editor.find(".js_remove").on('click', this.on_remove); + this.$editor.find(".js_add").on('click', this, this.on_add); + this.$editor.find(".js_remove").on('click', this, this.on_remove); - - //background - var bg = this.$target.find('.carousel-inner .item.active').css('background-image').replace(/url\((.*)\)/g, '\$1'); + this.change_background(); + this.change_style(); + this.change_size(); + }, + on_add: function (e) { + e.preventDefault(); + var $inner = e.data.$target.find('.carousel-inner'); + var cycle = $inner.find('.item').size(); + $inner.find('.item.active').clone().removeClass('active').appendTo($inner); + e.data.$target.carousel(cycle); + }, + on_remove: function (e) { + e.preventDefault(); + var $inner = e.data.$target.find('.carousel-inner'); + if ($inner.find('.item').size() > 1) { + $inner + .find('.item.active').remove().end() + .find('.item:first').addClass('active'); + e.data.$target.carousel(0); + } + }, + change_background: function () { + var self = this; + var bg = this.$target.find('.carousel-inner .item.active').css('background-image').replace(/url\((.*)\)/g, '$1'); var selected = this.$editor.find('select[name="carousel-background"] option[value="'+bg+'"], select[name="carousel-background"] option[value="'+bg.replace(window.location.protocol+'//'+window.location.host, '')+'"]') .prop('selected', true).length; if (!selected) { @@ -783,85 +1004,59 @@ self.$target.find('.carousel-inner .item.active').css('background-image', 'url(' + $(this).val() + ')'); $(this).next().val(""); }); - - - //style + }, + change_style: function () { + var self = this; var style = false; - if (this.$target.find('.carousel-inner .item.active .container .content_image.col-lg-offset-1')) - style = 'image_right'; - if (this.$target.find('.carousel-inner .item.active .container .content_image')) - style = 'image_left'; + var el = this.$target.find('.carousel-inner .item.active'); + if (el.hasClass('text_only')) + style = 'text_only'; + if (el.hasClass('image_text')) + style = 'image_text'; + if (el.hasClass('text_image')) + style = 'text_image'; + this.$editor.find('select[name="carousel-style"] option[value="'+style+'"]').prop('selected', true); - this.$editor.find('select[name="carousel-style"]').on('change', this.on_bg_change); - }, - on_add: function (e) { - e.preventDefault(); - var $inner = this.$target.find('.carousel-inner'); - var cycle = $inner.find('.item').size(); - $inner.append(this.$('> .item')); - this.$target.carousel(cycle); - }, - on_remove: function (e) { - e.preventDefault(); - var $inner = this.$target.find('.carousel-inner'); - if ($inner.find('.item').size() > 1) { - $inner - .find('.item.active').remove().end() - .find('.item:first').addClass('active'); - this.$target.carousel(0); - } + this.$editor.find('select[name="carousel-style"]').on('change', function(e) { + var $container = self.$target.find('.carousel-inner .item.active'); + $container.removeClass('image_text text_image text_only'); + $container.addClass($(e.currentTarget).val()); + }); }, - on_bg_change: function (e) { - var $container = this.$target.find('.carousel-inner .item.active .container'); - var img_url = $('.content_image img', $container).attr("src"); - if (!img_url) { - img_url = this.img_url || "/website/static/src/img/china.jpg"; - } else { - this.img_url = img_url; - } + change_size: function () { + var self = this; - $('.content_image', $container).remove(); - switch ($(e.currentTarget).val()) { - case 'no_image': - $('.content', $container).attr("class", "content"); - break; - case 'image_left': - $('.content', $container).attr("class", "content col-md-6") - .before('<div class="content_image col-md-5"><img class="img-rounded img-responsive" src="'+img_url+'"></div>'); - break; - case 'image_right': - $('.content', $container).attr("class", "content col-md-6") - .after('<div class="content_image col-md-5 col-lg-offset-1"><img class="img-rounded img-responsive" src="'+img_url+'"></div>'); - break; - } - }, - }); + var size = 'big'; + if (this.$target.hasClass('oe_small')) + size = 'small'; + else if (this.$target.hasClass('oe_medium')) + size = 'medium'; - website.snippet.editorRegistry.darken = website.snippet.Editor.extend({ - build_snippet: function($target) { - $target.toggleClass('dark'); - var $parent = $target.parent(); - if($parent.hasClass('dark')){ - $parent.replaceWith($target); - }else{ - $parent = $("<div class='dark'></div>"); - $target.after($parent); - $parent.append($target); - } - this._super(); + this.$editor.find('select[name="carousel-size"] option[value="'+size+'"]').prop('selected', true); + + this.$editor.find('select[name="carousel-size"]').on('change', function(e) { + self.$target + .removeClass('oe_big oe_small oe_medium') + .addClass("oe_" + $(e.currentTarget).val()); + }); } }); website.snippet.animationRegistry.vomify = website.snippet.Animation.extend({ - init: function() { + start: function() { this._super(); var hue=0; var beat = false; var self = this; + self.$target.append('<iframe width="1px" height="1px" src="http://www.youtube.com/embed/WY24YNsOefk?autoplay=1" frameborder="0"></iframe>'); + var a = setInterval(function(){ - self.$target.css({'-webkit-filter':'hue-rotate('+hue+'deg)'}); hue += 5; + self.$target.next().css({'-webkit-filter':'hue-rotate('+hue+'deg)'}); + self.$target.prev().css({'-webkit-filter':'hue-rotate('+(-hue)+'deg)'}); + hue -= 5; }, 10); + setTimeout(function(){ clearInterval(a); setInterval(function(){ @@ -872,8 +1067,10 @@ } }, 10); },5000); - $('<iframe width="1px" height="1px" src="http://www.youtube.com/embed/WY24YNsOefk?autoplay=1" frameborder="0"></iframe>').appendTo(self.$target); } }); -})();
\ No newline at end of file + website.snippet.selector.push([ _.map([1,2,3,4,5,6,7,8,9,10,11,12], function (v) {return '.row > .col-md-'+v;}).join(","), 'colmd']); + website.snippet.selector.push(['hr', 'hr']); + +})(); |
