diff --git a/addons/event_sale/event_demo.xml b/addons/event_sale/event_demo.xml index 3dee226119b..7ac1d5f2738 100644 --- a/addons/event_sale/event_demo.xml +++ b/addons/event_sale/event_demo.xml @@ -68,8 +68,10 @@ - 5000.0 + 1500.0 10 + Cathering for breakfast and lunch +VIP Parking access @@ -97,8 +99,10 @@ - 5000.0 + 1500.0 5 + Cathering for breakfast and lunch +VIP Parking access @@ -115,8 +119,10 @@ - 5000.0 + 1500.0 5 + Cathering for breakfast and lunch +VIP Parking access diff --git a/addons/website/__init__.py b/addons/website/__init__.py index d9cff35c01a..185183a2257 100644 --- a/addons/website/__init__.py +++ b/addons/website/__init__.py @@ -1,5 +1,3 @@ import controllers -import res_config -import website -import view +import models diff --git a/addons/website/controllers/main.py b/addons/website/controllers/main.py index 7b0ae426553..1bdeddb7107 100644 --- a/addons/website/controllers/main.py +++ b/addons/website/controllers/main.py @@ -14,7 +14,7 @@ import werkzeug.wrappers from PIL import Image import openerp -from openerp.addons.website import website +from openerp.addons.website.models import website from openerp.addons.web import http from openerp.addons.web.http import request diff --git a/addons/website/models/__init__.py b/addons/website/models/__init__.py new file mode 100644 index 00000000000..94d4412b1cf --- /dev/null +++ b/addons/website/models/__init__.py @@ -0,0 +1,6 @@ +# -*- coding: utf-8 -*- + +import ir_fields +import res_config +import view +import website diff --git a/addons/website/models/ir_fields.py b/addons/website/models/ir_fields.py new file mode 100644 index 00000000000..fbccf9c296d --- /dev/null +++ b/addons/website/models/ir_fields.py @@ -0,0 +1,87 @@ +# -*- coding: utf-8 -*- +from lxml import etree, html + +from openerp.osv import orm, fields +from openerp.tools import ustr + +class converter(orm.Model): + _inherit = 'ir.fields.converter' + + def _html_to_integer(self, cr, uid, model, column, value, context=None): + return int(value.text_content().strip()), [] + + def _html_to_float(self, cr, uid, model, column, value, context=None): + return float(value.text_content().strip()), [] + + def _html_to_passthrough(self, cr, uid, model, column, value, context=None): + return value.text_content().strip(), [] + + _html_to_char = _html_to_date = _html_to_datetime = _html_to_passthrough + + def _html_to_text(self, cr, uid, model, column, value, context=None): + return value.text_content(), [] + + def _html_to_selection(self, cr, uid, model, column, value, context=None): + text = value.text_content().strip() + + selection = column.reify(cr, uid, model, column, context=context) + for k, v in selection: + if isinstance(v, str): + v = ustr(v) + if text == v: + return k, [] + + warning = u"No value found for label %s in selection %s" % (text, selection) + # FIXME: ? + return False, [Warning(warning.encode('utf-8'))] + + def _html_to_many2one(self, cr, uid, model, column, value, context=None): + matches = self.pool[column._obj].name_search( + cr, uid, name=value.text_content().strip(), context=context) + # FIXME: more than one match, error reporting + return matches[0][0], [] + + def _html_to_html(self, cr, uid, model, column, value, context=None): + content = [] + if value.text: content.append(value.text) + content.extend(html.tostring(child) + for child in value.iterchildren(tag=etree.Element)) + return '\n'.join(content), [] + + +class test_converter(orm.Model): + _name = 'website.converter.test' + + _columns = { + 'char': fields.char(), + 'integer': fields.integer(), + 'float': fields.float(), + 'numeric': fields.float(digits=(16, 2)), + 'many2one': fields.many2one('website.converter.test.sub'), + 'binary': fields.binary(), + 'date': fields.date(), + 'datetime': fields.datetime(), + 'selection': fields.selection([ + (1, "réponse A"), + (2, "réponse B"), + (3, "réponse C"), + (4, "réponse D"), + ]), + 'selection_str': fields.selection([ + ('A', "Qu'il n'est pas arrivé à Toronto"), + ('B', "Qu'il était supposé arriver à Toronto"), + ('C', "Qu'est-ce qu'il fout ce maudit pancake, tabernacle ?"), + ('D', "La réponse D"), + ], string="Lorsqu'un pancake prend l'avion à destination de Toronto et " + "qu'il fait une escale technique à St Claude, on dit:"), + 'html': fields.html(), + 'text': fields.text(), + } + + +class test_converter_sub(orm.Model): + _name = 'website.converter.test.sub' + + _columns = { + 'name': fields.char(), + } diff --git a/addons/website/res_config.py b/addons/website/models/res_config.py similarity index 100% rename from addons/website/res_config.py rename to addons/website/models/res_config.py diff --git a/addons/website/view.py b/addons/website/models/view.py similarity index 66% rename from addons/website/view.py rename to addons/website/models/view.py index 6290a326fcf..6ddae129185 100644 --- a/addons/website/view.py +++ b/addons/website/models/view.py @@ -55,57 +55,19 @@ class view(osv.osv): def extract_embedded_fields(self, cr, uid, arch, context=None): return arch.xpath('//*[@data-oe-model != "ir.ui.view"]') - def convert_embedded_field(self, cr, uid, el, column, - type_override=None, context=None): - """ Converts the content of an embedded field to a value acceptable - for writing in the column - - :param etree._Element el: embedded field being saved - :param fields._column column: column object corresponding to the field - :param type type_override: column type to dispatch on instead of the - column's actual type (for proxy column types - e.g. relateds) - :return: converted value - """ - column_type = type_override or type(column) - - if issubclass(column_type, fields.html): - content = [] - if el.text: content.append(el.text) - content.extend(html.tostring(child) - for child in el.iterchildren(tag=etree.Element)) - return '\n'.join(content) - elif issubclass(column_type, fields.integer): - return int(el.text_content()) - elif issubclass(column_type, fields.float): - return float(el.text_content()) - elif issubclass(column_type, (fields.char, fields.text, - fields.date, fields.datetime)): - return el.text_content() - # TODO: fields.selection - elif issubclass(column_type, fields.many2one): - matches = self.pool[column._obj].name_search( - cr, uid, name=el.text_content().strip(), context=context) - # FIXME: more than one match, error reporting - return matches[0][0] - elif issubclass(column_type, fields.function): - # FIXME: special-case selection as in get_pg_type? - return self.convert_embedded_field( - cr, uid, el, column, - type_override=getattr(fields, column._type), - context=context) - # TODO?: fields.many2many, fields.one2many - # TODO?: fields.reference - else: - raise TypeError("Un-convertable column type %s" % column_type) - def save_embedded_field(self, cr, uid, el, context=None): Model = self.pool[el.get('data-oe-model')] field = el.get('data-oe-field') column = Model._all_columns[field].column + convert = self.pool['ir.fields.converter'].to_field( + cr, uid, Model, column, fromtype="html", context=context) + value, warnings = convert(el) + # FIXME: report error + if warnings: return + Model.write(cr, uid, [int(el.get('data-oe-id'))], { - field: self.convert_embedded_field(cr, uid, el, column, context=context) + field: value }, context=context) def to_field_ref(self, cr, uid, el, context=None): @@ -137,7 +99,8 @@ class view(osv.osv): """ res_id = int(res_id) - arch_section = html.fromstring(value) + arch_section = html.fromstring( + value, parser=html.HTMLParser(encoding='utf-8')) if xpath is None: # value is an embedded field on its own, not a view section diff --git a/addons/website/website.py b/addons/website/models/website.py similarity index 100% rename from addons/website/website.py rename to addons/website/models/website.py diff --git a/addons/website/static/src/css/editor.css b/addons/website/static/src/css/editor.css index 8a52aec47aa..2d1439f4f36 100644 --- a/addons/website/static/src/css/editor.css +++ b/addons/website/static/src/css/editor.css @@ -1,4 +1,4 @@ -@charset "utf-8"; +@charset "UTF-8"; /* ---- CKEditor Minimal Reset ---- */ .navbar.navbar-inverse .cke_chrome { border: none; @@ -167,7 +167,6 @@ table.editorbar-panel td.selected { box-shadow: 0px 10px 10px -10px black inset; z-index: 1010; overflow: hidden; - height: 110px; } #oe_snippets:hover { height: auto; @@ -177,16 +176,13 @@ table.editorbar-panel td.selected { overflow-y: auto; } #oe_snippets .nav { - padding: 3px 15px; - width: 162px; - background: #444444; position: fixed; z-index: 1; - height: 108px; } #oe_snippets .nav > li { - display: block; + display: inline-block; float: none; + font-size: 13px; } #oe_snippets .nav > li > a { padding: 2px 10px !important; @@ -194,13 +190,14 @@ table.editorbar-panel td.selected { display: block; } #oe_snippets .pill-content { + margin-top: 24px; display: inline-block; - height: 110px; white-space: nowrap; - padding-left: 166px; } #oe_snippets .pill-content > div { display: inline-block; + background: black; + padding: 5px; } #oe_snippets .pill-content > div label { width: 44px; @@ -211,23 +208,23 @@ table.editorbar-panel td.selected { #oe_snippets .pill-content > div label div { width: 100px; text-align: center; - -webkit-transform: translate(-39px, 44px) rotate(-90deg); - -moz-transform: translate(-39px, 44px) rotate(-90deg); - -o-transform: translate(-39px, 44px) rotate(-90deg); - transform: translate(-39px, 44px) rotate(-90deg); - -webkit-transform-origin: 50% 50%; - -moz-transform-origin: 50% 50%; - -ms-transform-origin: 50% 50%; - -o-transform-origin: 50% 50%; - transform-origin: 50% 50%; + -webkit-transform: translate(-39px, 44px); + -moz-transform: translate(-39px, 44px); + -ms-transform: translate(-39px, 44px); + -o-transform: translate(-39px, 44px); + transform: translate(-39px, 44px); + -webkit-transform-origin: 50% 50% 50%; + -moz-transform-origin: 50% 50% 50%; + -ms-transform-origin: 50% 50% 50%; + -o-transform-origin: 50% 50% 50%; + transform-origin: 50% 50% 50%; } .oe_snippet { display: inline-block; vertical-align: top; - width: 108px; - height: 108px; - border-radius: 3px; + width: 100px; + height: 100px; margin: 1px; margin-top: 0px; position: relative; @@ -243,9 +240,15 @@ table.editorbar-panel td.selected { height: 100%; background: transparent; color: white; - text-shadow: 0px 1px 2px rgba(0, 0, 0, 0.95); position: relative; } +.oe_snippet .oe_snippet_thumbnail .oe_snippet_thumbnail_title { + font-size: 12px; + display: block; +} +.oe_snippet .oe_snippet_thumbnail .oe_snippet_thumbnail_img { + box-shadow: inset 0px 0px 0px 3px #333333; +} .oe_snippet .oe_snippet_thumbnail span, .oe_snippet .oe_snippet_thumbnail div { line-height: 18px; } @@ -256,7 +259,6 @@ table.editorbar-panel td.selected { #oe_snippets .oe_snippet_thumbnail { background: #747474; background-image: radial-gradient(rgba(0, 0, 0, 0.25), rgba(0, 0, 0, 0.4)); - box-shadow: 0px 0px 0px 1px rgba(255, 255, 255, 0.07) inset; } /* ---- SNIPPETS DROP ZONES ---- */ diff --git a/addons/website/static/src/css/editor.sass b/addons/website/static/src/css/editor.sass index 54c6b6576de..0a126bb3197 100644 --- a/addons/website/static/src/css/editor.sass +++ b/addons/website/static/src/css/editor.sass @@ -1,5 +1,7 @@ @charset "utf-8" +@import "compass/css3" + /* ---- CKEditor Minimal Reset ---- */ .navbar.navbar-inverse .cke_chrome @@ -145,33 +147,30 @@ table.editorbar-panel box-shadow: 0px 10px 10px -10px black inset z-index: 1010 overflow: hidden - height: 110px &:hover height: auto .scroll white-space: nowrap overflow-y: auto .nav - padding: 3px 15px - width: 162px - background: #444444 > li - display: block + display: inline-block float: none + font-size: 13px > a padding: 2px 10px !important width: 100% display: block position: fixed z-index: 1 - height: 108px .pill-content + margin-top: 24px display: inline-block - height: 110px white-space: nowrap - padding-left: 166px > div display: inline-block + background: rgb(0,0,0) + padding: 5px label width: 44px height: 100% @@ -180,22 +179,14 @@ table.editorbar-panel div width: 100px text-align: center - -webkit-transform: translate(-39px, 44px) rotate(-90deg) - -moz-transform: translate(-39px, 44px) rotate(-90deg) - -o-transform: translate(-39px, 44px) rotate(-90deg) - transform: translate(-39px, 44px) rotate(-90deg) - -webkit-transform-origin: 50% 50% - -moz-transform-origin: 50% 50% - -ms-transform-origin: 50% 50% - -o-transform-origin: 50% 50% - transform-origin: 50% 50% + @include transform( translate(-39px, 44px) , rotate(-90deg) ) + @include transform-origin(50% 50%) .oe_snippet display: inline-block vertical-align: top - width: 108px - height: 108px - border-radius: 3px + width: 100px + height: 100px margin: 1px margin-top: 0px position: relative @@ -204,15 +195,18 @@ table.editorbar-panel user-select: none cursor: move pointer-events: none - .oe_snippet_thumbnail pointer-events: auto text-align: center height: 100% background: transparent color: white - text-shadow: 0px 1px 2px rgba(0, 0, 0, 0.95) position: relative + .oe_snippet_thumbnail_title + font-size: 12px + display: block + .oe_snippet_thumbnail_img + box-shadow: inset 0px 0px 0px 3px #333333 span, div line-height: 18px & > :not(.oe_snippet_thumbnail) @@ -221,7 +215,6 @@ table.editorbar-panel #oe_snippets .oe_snippet_thumbnail background: rgb(116, 116, 116) background-image: radial-gradient(rgba(0,0,0,0.25),rgba(0,0,0,0.4)) - box-shadow: 0px 0px 0px 1px rgba(255, 255, 255, 0.07) inset /* ---- SNIPPETS DROP ZONES ---- */ diff --git a/addons/website/static/src/css/website.css b/addons/website/static/src/css/website.css index 80057dbf21d..1796729f18c 100644 --- a/addons/website/static/src/css/website.css +++ b/addons/website/static/src/css/website.css @@ -367,6 +367,25 @@ ul.nav-stacked > li > a { } /* ---- PUBLISH ---- */ +a[data-publish] { + text-decoration: none !important; +} +a[data-publish] .css_unpublish, a[data-publish] .css_publish, a[data-publish] .css_unpublished, a[data-publish] .css_published { + display: none; +} +a[data-publish][data-publish='off'] .css_unpublished, a[data-publish][data-publish='off']:hover .css_publish { + display: inline; +} +a[data-publish][data-publish='off']:hover .css_unpublished { + display: none; +} +a[data-publish][data-publish='on'] .css_published, a[data-publish][data-publish='on']:hover .css_unpublish { + display: inline; +} +a[data-publish][data-publish='on']:hover .css_published { + display: none; +} + .dropdown .css_unpublish, .dropdown .css_publish { display: none; } diff --git a/addons/website/static/src/css/website.sass b/addons/website/static/src/css/website.sass index b1f43b543a3..9834fb66aed 100644 --- a/addons/website/static/src/css/website.sass +++ b/addons/website/static/src/css/website.sass @@ -283,6 +283,20 @@ ul.nav-stacked > li > a text-transform: uppercase /* ---- PUBLISH ---- */ +a[data-publish] + text-decoration: none !important + .css_unpublish, .css_publish, .css_unpublished, .css_published + display: none + &[data-publish='off'] + .css_unpublished, &:hover .css_publish + display: inline + &:hover .css_unpublished + display: none + &[data-publish='on'] + .css_published, &:hover .css_unpublish + display: inline + &:hover .css_published + display: none .dropdown .css_unpublish, .dropdown .css_publish display: none diff --git a/addons/website/static/src/img/blocks/block_banner.png b/addons/website/static/src/img/blocks/block_banner.png new file mode 100644 index 00000000000..305ffb8855b Binary files /dev/null and b/addons/website/static/src/img/blocks/block_banner.png differ diff --git a/addons/website/static/src/img/blocks/block_big_picture.png b/addons/website/static/src/img/blocks/block_big_picture.png new file mode 100644 index 00000000000..8fd913efcdc Binary files /dev/null and b/addons/website/static/src/img/blocks/block_big_picture.png differ diff --git a/addons/website/static/src/img/blocks/block_button.png b/addons/website/static/src/img/blocks/block_button.png new file mode 100644 index 00000000000..8daf48ec3bc Binary files /dev/null and b/addons/website/static/src/img/blocks/block_button.png differ diff --git a/addons/website/static/src/img/blocks/block_comparison.png b/addons/website/static/src/img/blocks/block_comparison.png new file mode 100644 index 00000000000..610f7658e96 Binary files /dev/null and b/addons/website/static/src/img/blocks/block_comparison.png differ diff --git a/addons/website/static/src/img/blocks/block_faq.png b/addons/website/static/src/img/blocks/block_faq.png new file mode 100644 index 00000000000..fe0f819143b Binary files /dev/null and b/addons/website/static/src/img/blocks/block_faq.png differ diff --git a/addons/website/static/src/img/blocks/block_image_gallery.png b/addons/website/static/src/img/blocks/block_image_gallery.png new file mode 100644 index 00000000000..2b70ce2557a Binary files /dev/null and b/addons/website/static/src/img/blocks/block_image_gallery.png differ diff --git a/addons/website/static/src/img/blocks/block_image_text.png b/addons/website/static/src/img/blocks/block_image_text.png new file mode 100644 index 00000000000..01bf9861066 Binary files /dev/null and b/addons/website/static/src/img/blocks/block_image_text.png differ diff --git a/addons/website/static/src/img/blocks/block_jumbotron.png b/addons/website/static/src/img/blocks/block_jumbotron.png new file mode 100644 index 00000000000..656f9591998 Binary files /dev/null and b/addons/website/static/src/img/blocks/block_jumbotron.png differ diff --git a/addons/website/static/src/img/blocks/block_panel.png b/addons/website/static/src/img/blocks/block_panel.png new file mode 100644 index 00000000000..c4d66975905 Binary files /dev/null and b/addons/website/static/src/img/blocks/block_panel.png differ diff --git a/addons/website/static/src/img/blocks/block_parallax.png b/addons/website/static/src/img/blocks/block_parallax.png new file mode 100644 index 00000000000..693da297cef Binary files /dev/null and b/addons/website/static/src/img/blocks/block_parallax.png differ diff --git a/addons/website/static/src/img/blocks/block_portfolio.png b/addons/website/static/src/img/blocks/block_portfolio.png new file mode 100644 index 00000000000..40102160f96 Binary files /dev/null and b/addons/website/static/src/img/blocks/block_portfolio.png differ diff --git a/addons/website/static/src/img/blocks/block_quote.png b/addons/website/static/src/img/blocks/block_quote.png new file mode 100644 index 00000000000..8c3d082219b Binary files /dev/null and b/addons/website/static/src/img/blocks/block_quote.png differ diff --git a/addons/website/static/src/img/blocks/block_references.png b/addons/website/static/src/img/blocks/block_references.png new file mode 100644 index 00000000000..c7164d36b7a Binary files /dev/null and b/addons/website/static/src/img/blocks/block_references.png differ diff --git a/addons/website/static/src/img/blocks/block_separator.png b/addons/website/static/src/img/blocks/block_separator.png new file mode 100644 index 00000000000..293d83ee398 Binary files /dev/null and b/addons/website/static/src/img/blocks/block_separator.png differ diff --git a/addons/website/static/src/img/blocks/block_surprise.png b/addons/website/static/src/img/blocks/block_surprise.png new file mode 100644 index 00000000000..e01382a5ab1 Binary files /dev/null and b/addons/website/static/src/img/blocks/block_surprise.png differ diff --git a/addons/website/static/src/img/blocks/block_text_block.png b/addons/website/static/src/img/blocks/block_text_block.png new file mode 100644 index 00000000000..df2c96de997 Binary files /dev/null and b/addons/website/static/src/img/blocks/block_text_block.png differ diff --git a/addons/website/static/src/img/blocks/block_text_image.png b/addons/website/static/src/img/blocks/block_text_image.png new file mode 100644 index 00000000000..4e275fcc22a Binary files /dev/null and b/addons/website/static/src/img/blocks/block_text_image.png differ diff --git a/addons/website/static/src/img/blocks/block_three_columns.png b/addons/website/static/src/img/blocks/block_three_columns.png new file mode 100644 index 00000000000..5cc49b3319e Binary files /dev/null and b/addons/website/static/src/img/blocks/block_three_columns.png differ diff --git a/addons/website/static/src/img/blocks/block_title.png b/addons/website/static/src/img/blocks/block_title.png new file mode 100644 index 00000000000..2e28ea0a068 Binary files /dev/null and b/addons/website/static/src/img/blocks/block_title.png differ diff --git a/addons/website/static/src/img/blocks/blocks-icons.png b/addons/website/static/src/img/blocks/blocks-icons.png new file mode 100644 index 00000000000..94c82f3f309 Binary files /dev/null and b/addons/website/static/src/img/blocks/blocks-icons.png differ diff --git a/addons/website/static/src/js/website.editor.js b/addons/website/static/src/js/website.editor.js index 8b15422b90d..f40ccea715b 100644 --- a/addons/website/static/src/js/website.editor.js +++ b/addons/website/static/src/js/website.editor.js @@ -18,7 +18,7 @@ return new website.editor.LinkDialog(editor).appendTo(document.body); } function image_dialog(editor) { - return new website.editor.ImageDialog(editor).appendTo(document.body); + return new website.editor.RTEImageDialog(editor).appendTo(document.body); } if (website.is_editable) { @@ -673,6 +673,23 @@ }); }, }); + /** + * ImageDialog widget. Lets users change an image, including uploading a + * new image in OpenERP or selecting the image style (if supported by + * the caller). + * + * Initialized as usual, but the caller can hook into two events: + * + * @event start({url, style}) called during dialog initialization and + * opening, the handler can *set* the ``url`` + * and ``style`` properties on its parameter + * to provide these as default values to the + * dialog + * @event save({url, style}) called during dialog finalization, the handler + * is provided with the image url and style + * selected by the users (or possibly the ones + * originally passed in) + */ website.editor.ImageDialog = website.editor.Dialog.extend({ template: 'website.editor.dialog.image', events: _.extend({}, website.editor.Dialog.prototype.events, { @@ -685,47 +702,30 @@ '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(); + start: function () { + var $options = this.$('.image-style').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')); + var o = { url: null, style: null, }; + // avoid typos, prevent addition of new properties to the object + Object.preventExtensions(o); + this.trigger('start', o); + + if (o.url) { + if (o.style) { + this.$('.image-style').val(o.style); + } + this.set_image(o.url); } 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'); - // focus event handler interactions between bootstrap (modal) - // and ckeditor (RTE) lead to blowing the stack in Safari and - // Chrome (but not FF) when this is done synchronously => - // defer insertion so modal has been hidden & destroyed before - // it happens - setTimeout(function () { - editor.insertElement(element); - }, 0); - } - element.setAttribute('src', url); - $(element.$).removeClass(this.image_styles.join(' ')); - if (style) { element.addClass(style); } - + this.trigger('save', { + url: this.$('input.url').val(), + style: this.$('.image-style').val(), + }); return this._super(); }, @@ -769,12 +769,53 @@ .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); }, }); + website.editor.RTEImageDialog = website.editor.ImageDialog.extend({ + init: function () { + this._super.apply(this, arguments); + + this.on('start', this, this.proxy('started')); + this.on('save', this, this.proxy('saved')); + }, + started: function (holder) { + var selection = this.editor.getSelection(); + var el = selection && selection.getSelectedElement(); + this.element = null; + + if (el && el.is('img')) { + this.element = el; + _(this.image_styles).each(function (style) { + if (el.hasClass(style)) { + holder.style = style; + } + }); + holder.url = el.getAttribute('src'); + } + }, + saved: function (data) { + var element, editor = this.editor; + if (!(element = this.element)) { + element = editor.document.createElement('img'); + // focus event handler interactions between bootstrap (modal) + // and ckeditor (RTE) lead to blowing the stack in Safari and + // Chrome (but not FF) when this is done synchronously => + // defer insertion so modal has been hidden & destroyed before + // it happens + setTimeout(function () { + editor.insertElement(element); + }, 0); + } + + var style = data.style; + element.setAttribute('src', data.url); + $(element.$).removeClass(this.image_styles.join(' ')); + if (style) { element.addClass(style); } + }, + }); var IMAGES_PER_ROW = 6; var IMAGES_ROWS = 4; @@ -893,7 +934,7 @@ if (m.attributeName !== 'class') { return true; } // find out what classes were added or removed - var oldClasses = m.oldValue.split(/\s+/); + var oldClasses = (m.oldValue || '').split(/\s+/); var newClasses = m.target.className.split(/\s+/); var change = _.union(_.difference(oldClasses, newClasses), _.difference(newClasses, oldClasses)); @@ -911,6 +952,7 @@ while (node && !$(node).hasClass('oe_editable')) { node = node.parentNode; } + $(m.target).trigger('node_changed'); return node; }) .compact() diff --git a/addons/website/static/src/js/website.js b/addons/website/static/src/js/website.js index bc0db10ce88..e524edfb389 100644 --- a/addons/website/static/src/js/website.js +++ b/addons/website/static/src/js/website.js @@ -117,9 +117,29 @@ }; dom_ready.then(function () { + /* ----- PUBLISHING STUFF ---- */ + $('[data-publish]:has(.js_publish)').each(function () { + var $pub = $("[data-publish]", this); + if($pub.size()) + $(this).attr("data-publish", $pub.attr("data-publish")); + else + $(this).removeAttr("data-publish"); + }); + $('[data-publish]:has(.js_publish_management)').each(function () { $(this).attr("data-publish", $(".js_publish_management .btn-success", this).size() ? "on" : 'off'); + $(this).attr("data-publish", $(".js_publish_management .btn-success", this).size() ? "on" : 'off'); + }); + + $(document).on('click', '.js_publish', function (e) { + e.preventDefault(); + var $data = $(":first", this).parents("[data-publish]"); + $data.attr("data-publish", $data.first().attr("data-publish") == 'off' ? 'on' : 'off'); + openerp.jsonRpc('/website/publish', 'call', {'id': $(this).data('id'), 'object': $(this).data('object')}) + .then(function (result) { + $data.attr("data-publish", +result ? 'on' : 'off'); + }); }); $(document).on('click', '.js_publish_management .js_publish_btn', function (e) { diff --git a/addons/website/static/src/js/website.snippets.js b/addons/website/static/src/js/website.snippets.js index 9a6ade27992..3de2ddaeabb 100644 --- a/addons/website/static/src/js/website.snippets.js +++ b/addons/website/static/src/js/website.snippets.js @@ -8,8 +8,8 @@ start: function () { var self = this; $("[data-oe-model]").on('click', function (event) { - var tag = event.srcElement.tagName.toLowerCase(); var $this = $(event.srcElement); + var tag = $this[0].tagName.toLowerCase(); if (!(tag === 'a' || tag === "button") && !$this.parents("a, button").length) { self.$('[data-action="edit"]').parent().effect('bounce', {distance: 18, times: 5}, 250); } @@ -158,23 +158,29 @@ var $pill = self.$(".pill-content"); var padding = parseInt($pill.css("padding-left")); var $scroll = this.$(".scroll"); - - $scroll.scroll(function () { + + $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'); - } + }*/ }); }); $ul.find("a").click(function (event) { event.preventDefault(); - $scroll.scrollLeft( $scroll.scrollLeft() + $($(event.currentTarget).attr("href")).position().left - padding ); + $pill.find("> div").hide(); + $pill.find( $(event.currentTarget).attr('href')).show(); + $ul.find('> li').removeClass('active'); + $(event.currentTarget).parent().addClass('active'); return false; }); - $pill.css("padding-right", self.$el.outerWidth() - padding + 10 - $pill.find("> div:last").outerWidth()); + // $pill.css("padding-right", self.$el.outerWidth() - padding + 10 - $pill.find("> div:last").outerWidth()); + $pill.find("> div").hide(); + $pill.find("div:first").show(); $ul.find("> li:first").addClass('active'); }, cover_target: function ($el, $target){ @@ -389,7 +395,7 @@ }, stop: function(){ $('.oe_drop_zone').droppable('destroy').remove(); - if (!dropped) { + if (!dropped && self.$modal.find('input:not(:checked)').length) { self.$modal.modal('toggle'); } }, @@ -573,7 +579,6 @@ onBlurEdit : function () {}, }); - website.snippet.editorRegistry = {}; website.snippet.Editor = openerp.Class.extend({ init: function (parent, dom) { @@ -700,6 +705,7 @@ this.$overlay.on('click', '.oe_snippet_clone', function () { var $clone = self.$target.clone(false); self.$target.after($clone); + return false; }); }, @@ -793,6 +799,50 @@ onBlur : function () { this.$overlay.removeClass('oe_active'); }, + + change_background: function (bg, ul_options) { + var self = this; + var $ul = this.$editor.find(ul_options); + var bg_value = (typeof bg == 'string' ? self.$target.find(bg) : $(bg)).css("background-image").replace(/url\(['"]*|['"]*\)/g, ""); + + // select in ul options + $ul.find("li").removeClass("active"); + var selected = $ul.find('[data-value="' + bg_value + '"], [data-value="' + bg_value.replace(/.*:\/\/[^\/]+/, '') + '"]'); + selected.addClass('active'); + if (!selected.length) { + $ul.find('.oe_custom_bg b').html(bg_value); + } + + // bind envent on options + var $li = $ul.find("li"); + $li.on('click', function (event) { + if ($(this).data("value")) { + $li.removeClass("active"); + $(this).addClass("active"); + self.$editor.find('input').val(""); + } else { + var editor = new website.editor.ImageDialog(); + editor.on('start', self, function (o) {o.url = bg_value;}); + editor.on('save', self, function (o) { + var $bg = typeof bg == 'string' ? self.$target.find(bg) : $(bg); + $bg.css("background-image", "url(" + o.url + ")"); + }); + editor.appendTo($('body')); + } + }) + .on('mouseover', function (event) { + if ($(this).data("value")) { + var src = $(this).data("value"); + var $bg = typeof bg == 'string' ? self.$target.find(bg) : $(bg); + $bg.css("background-image", "url(" + src + ")"); + } + }) + .on('mouseout', function (event) { + var src = $ul.find('li.active').data("value"); + var $bg = typeof bg == 'string' ? self.$target.find(bg) : $(bg); + $bg.css("background-image", "url(" + src + ")"); + }); + }, }); @@ -863,13 +913,13 @@ var change = false; if (dd > (2*resize[1][next] + resize[1][current])/3) { - self.$target.attr("class",self.$target.attr("class").replace(regClass, '')); + self.$target.attr("class", (self.$target.attr("class")||'').replace(regClass, '')); self.$target.addClass(resize[0][next]); current = next; change = true; } if (prev != current && dd < (2*resize[1][prev] + resize[1][current])/3) { - self.$target.attr("class",self.$target.attr("class").replace(regClass, '')); + self.$target.attr("class", (self.$target.attr("class")||'').replace(regClass, '')); self.$target.addClass(resize[0][prev]); current = prev; change = true; @@ -991,8 +1041,9 @@ this.$editor.find(".js_add").on('click', _.bind(this.on_add, this)); this.$editor.find(".js_remove").on('click', _.bind(this.on_remove, this)); - this.change_background(); + this.change_background(".item.active", 'ul[name="carousel-background"]'); this.change_style(); + this.set_options_style(); this.change_size(); }, on_add: function (e) { @@ -1014,48 +1065,12 @@ .find('.item.active').remove().end() .find('.item:first').addClass('active'); this.$target.carousel(0); - this.set_options_background(); this.set_options_style(); } if (nb <= 1) { this.$target.find('.carousel-control').addClass("hidden"); } }, - onFocus: function () { - this.set_options_background(); - this.set_options_style(); - this._super(); - }, - set_options_background: function () { - var $image = this.$target.find('.carousel-inner .item.active > img'); - var bg = $image.attr('src'); - var $ul = this.$editor.find('ul[name="carousel-background"]'); - $ul.find("li").removeClass("active"); - var selected = $ul.find('[data-value="' + bg + '"], [data-value="' + bg.replace(/.*:\/\/[^\/]+/, '') + '"]') - .addClass('active').length; - this.$editor.find('.oe_custom_bg b').html(selected ? "" : bg); - }, - change_background: function () { - var self = this; - var $ul = this.$editor.find('ul[name="carousel-background"]'); - var $li = $ul.find("li"); - - $li.on('click', function (event) { - $li.removeClass("active"); - $(this).addClass("active"); - self.$editor.find('input').val(""); - }) - .on('mouseover', function (event) { - if ($(this).data("value")) { - self.$target.find('.carousel-inner .item.active > img') - .attr('src', $(this).data("value")); - } - }) - .on('mouseout', function (event) { - self.$target.find('.carousel-inner .item.active > img') - .attr('src', $ul.find('li.active').data("value")); - }); - }, set_options_style: function () { var style = false; var $el = this.$target.find('.carousel-inner .item.active'); @@ -1124,50 +1139,7 @@ website.snippet.editorRegistry.parallax = website.snippet.editorRegistry.resize.extend({ start : function () { this._super(); - this.change_background(); - }, - onFocus: function () { - this.$imagebg = $(""); - this.$imagebg.prependTo(this.$target); - this.set_options_background(); - this._super(); - }, - onBlur : function () { - this._super(); - this.$imagebg.remove(); - }, - set_options_background: function () { - var bg = this.$target.css("background-image").replace(/url\(|\)/g, ""); - this.$imagebg.attr("src", bg); - - var $ul = this.$editor.find('ul[name="parallax-background"]'); - $ul.find("li").removeClass("active"); - var selected = $ul.find('[data-value="' + bg + '"], [data-value="' + bg.replace(/.*:\/\/[^\/]+/, '') + '"]') - .addClass('active').length; - this.$editor.find('.oe_custom_bg b').html(selected ? "" : bg); - }, - change_background: function () { - var self = this; - var $ul = this.$editor.find('ul[name="parallax-background"]'); - var $li = $ul.find("li"); - - $li.on('click', function (event) { - $li.removeClass("active"); - $(this).addClass("active"); - self.$editor.find('input').val(""); - }) - .on('mouseover', function (event) { - if ($(this).data("value")) { - var src = $(this).data("value"); - self.$imagebg.attr('src', src); - self.$target.css("background-image", "url(" + src + ")"); - } - }) - .on('mouseout', function (event) { - var src = $ul.find('li.active').data("value"); - self.$imagebg.attr('src', src); - self.$target.css("background-image", "url(" + src + ")"); - }); + this.change_background(this.$target, 'ul[name="parallax-background"]'); }, }); diff --git a/addons/website/static/src/xml/website.snippets.xml b/addons/website/static/src/xml/website.snippets.xml index 05146e5f34f..263c383ff4b 100644 --- a/addons/website/static/src/xml/website.snippets.xml +++ b/addons/website/static/src/xml/website.snippets.xml @@ -63,10 +63,10 @@
  • Effects
  • -
    -
    -
    -
    +
    +
    +
    +
    @@ -160,17 +160,14 @@
    - - - Banner + + Banner
    -