diff --git a/addons/website/static/src/css/editor.css b/addons/website/static/src/css/editor.css index df098f28353..d52729756a7 100644 --- a/addons/website/static/src/css/editor.css +++ b/addons/website/static/src/css/editor.css @@ -137,6 +137,7 @@ table.editorbar-panel td.selected { line-height: 120px; color: white; text-shadow: 0px 1px 2px rgba(0, 0, 0, 0.95); + box-shadow: 0px 0px 0px 1px rgba(255, 255, 255, 0.07) inset; } .oe_snippet .oe_snippet_body { display: none; @@ -144,6 +145,9 @@ table.editorbar-panel td.selected { .oe_snippet > * { pointer-events: none; } +.oe_snippet > :not(.oe_snippet_body):not(.oe_snippet_thumbnail) { + display: none !important; +} .oe_snippet > *:first-child:not(.oe_snippet_thumbnail) { display: block; -webkit-transform-origin-x: 5px; @@ -202,35 +206,68 @@ table.editorbar-panel td.selected { .oe_snippet_manipulator { display: block; position: absolute; - background: rgba(153, 0, 255, 0.1); + background: transparent; border-radius: 3px; - border: solid 1px rgba(153, 0, 255, 0.5); opacity: 0; transition: opacity 100ms linear; + box-sizing: border-box; + pointer-events: none; } -.oe_snippet_manipulator > .oe_handle { +.oe_snippet_manipulator .oe_boxsize, .oe_snippet_manipulator .oe_margin { + position: absolute; + pointer-events: none; +} +.oe_snippet_manipulator .oe_handle { display: none; } -.oe_snippet_manipulator:hover, .oe_snippet_manipulator.oe_hover { +.oe_snippet_manipulator.oe_hover { opacity: 1; + cursor: pointer; } -.oe_snippet_manipulator:hover > .oe_handle, .oe_snippet_manipulator.oe_hover > .oe_handle { +.oe_snippet_manipulator.oe_selected, .oe_snippet_manipulator.oe_active, .oe_snippet_manipulator .oe_boxsize, .oe_snippet_manipulator .oe_margin { + opacity: 1; + background: transparent; + border: dashed 1px rgba(153, 0, 255, 0.5); + box-shadow: 0px 0px 0px 1px rgba(255, 255, 255, 0.3), 0px 0px 0px 1px rgba(255, 255, 255, 0.3) inset; +} +.oe_snippet_manipulator.oe_selected .oe_handle, .oe_snippet_manipulator.oe_active .oe_handle, .oe_snippet_manipulator .oe_boxsize .oe_handle, .oe_snippet_manipulator .oe_margin .oe_handle { + pointer-events: auto; +} +.oe_snippet_manipulator .oe_buttons { + display: none; + position: absolute; + right: 16px; + top: 16px; + background: #ad00ff; + color: white; + padding: 0px 2px; + border-radius: 3px; +} +.oe_snippet_manipulator .oe_buttons .oe_icon { + display: inline-block; + padding: 8px; + cursor: pointer; +} +.oe_snippet_manipulator.oe_active { + z-index: 100000; +} +.oe_snippet_manipulator.oe_active .oe_handle, .oe_snippet_manipulator.oe_active .oe_buttons { display: block; } .oe_handle { + pointer-events: auto; position: absolute; top: 50%; left: 50%; display: block; background: white; - border: solid 1px rgba(153, 0, 255, 0.5); + border: solid 1px #9900ff; box-sizing: border-box; - border-radius: 2px; + border-radius: 8px; width: 16px; height: 16px; margin: -8px; - cursor: move; -webkit-transition: background 100ms linear; } .oe_handle:hover { @@ -255,6 +292,38 @@ table.editorbar-panel td.selected { left: 0px; } +.oe_handle.n { + cursor: n-resize; +} + +.oe_handle.ne { + cursor: ne-resize; +} + +.oe_handle.nw { + cursor: nw-resize; +} + +.oe_handle.s { + cursor: s-resize; +} + +.oe_handle.se { + cursor: se-resize; +} + +.oe_handle.sw { + cursor: sw-resize; +} + +.oe_handle.e { + cursor: e-resize; +} + +.oe_handle.w { + cursor: w-resize; +} + /* ---- MOBILE PREVIEW ---- */ .oe_mobile_preview.modal .modal-content { height: 660px; diff --git a/addons/website/static/src/css/editor.sass b/addons/website/static/src/css/editor.sass index 2da2b4bbeeb..289ab1e6e54 100644 --- a/addons/website/static/src/css/editor.sass +++ b/addons/website/static/src/css/editor.sass @@ -129,11 +129,14 @@ table.editorbar-panel line-height: 120px color: white text-shadow: 0px 1px 2px rgba(0, 0, 0, 0.95) + box-shadow: 0px 0px 0px 1px rgba(255, 255, 255, 0.07) inset .oe_snippet_body display: none & > * pointer-events: none + & > :not(.oe_snippet_body):not(.oe_snippet_thumbnail) + display: none !important & > *:first-child:not(.oe_snippet_thumbnail) display: block @@ -186,31 +189,58 @@ table.editorbar-panel .oe_snippet_manipulator display: block position: absolute - background: rgba(153, 0, 255, 0.1) + background: transparent //rgba(153, 0, 255, 0.05) border-radius: 3px - border: solid 1px rgba(153, 0, 255, 0.5) opacity: 0 transition: opacity 100ms linear - & > .oe_handle + box-sizing: border-box + pointer-events: none + .oe_boxsize, .oe_margin + position: absolute + pointer-events: none + .oe_handle display: none - &:hover,&.oe_hover + &.oe_hover opacity: 1 - & > .oe_handle + cursor: pointer + &.oe_selected, &.oe_active, .oe_boxsize, .oe_margin + opacity: 1 + background: transparent + border: dashed 1px rgba(153, 0, 255, 0.5) + box-shadow: 0px 0px 0px 1px rgba(255,255,255,0.3), 0px 0px 0px 1px rgba(255,255,255,0.3) inset + .oe_handle + pointer-events: auto + .oe_buttons + display: none + position: absolute + right: 16px + top: 16px + background: rgb(173, 0, 255) + color: white + padding: 0px 2px + border-radius: 3px + .oe_icon + display: inline-block + padding: 8px + cursor: pointer + &.oe_active + z-index: 100000 + .oe_handle, .oe_buttons display: block .oe_handle + pointer-events: auto position: absolute top: 50% left: 50% display: block background: rgba(255, 255, 255, 1) - border: solid 1px rgba(153, 0, 255, 0.5) + border: solid 1px rgba(153, 0, 255, 1) box-sizing: border-box - border-radius: 2px + border-radius: 8px width: 16px height: 16px margin: -8px - cursor: move -webkit-transition: background 100ms linear &:hover background: rgb(153, 0, 255) @@ -225,6 +255,23 @@ table.editorbar-panel bottom: 0px .oe_handle.nw,.oe_handle.w,.oe_handle.sw left: 0px +.oe_handle.n + cursor: n-resize +.oe_handle.ne + cursor: ne-resize +.oe_handle.nw + cursor: nw-resize +.oe_handle.s + cursor: s-resize +.oe_handle.se + cursor: se-resize +.oe_handle.sw + cursor: sw-resize +.oe_handle.e + cursor: e-resize +.oe_handle.w + cursor: w-resize + /* ---- MOBILE PREVIEW ---- */ diff --git a/addons/website/static/src/css/snippets.css b/addons/website/static/src/css/snippets.css index c9b726affde..0eeab9aee99 100644 --- a/addons/website/static/src/css/snippets.css +++ b/addons/website/static/src/css/snippets.css @@ -88,7 +88,7 @@ padding: 8px; } -.oe_snippet_editor .oe_snippet.oe_selected{ +.oe_snippet_editor .oe_snippet.oe_selected, .oe_snippet_editor .oe_snippet.oe_active{ border: 2px solid rgb(151, 137, 255); box-shadow: 0px 3px 17px rgba(99, 53, 150, 0.59); @@ -134,7 +134,7 @@ box-shadow: 0px 1px 3px rgb(90,90,90) inset; border: 0px; } -.oe_snippet_editor .oe_snippet.oe_new.oe_selected{ +.oe_snippet_editor .oe_snippet.oe_new.oe_selected, .oe_snippet_editor .oe_snippet.oe_new.oe_active{ box-shadow: 0px 2px 0px 0px rgb(151,137,255) inset, 0px 3px 17px rgba(99, 53, 150, 0.59) inset; } .oe_snippet_editor .oe_snippet.oe_new > *{ @@ -176,3 +176,29 @@ margin-left: 0px !important; } */ + +#website-top-edit li.oe_snippet_editorbar { + padding: 1px 8px 2px; + font: normal normal normal 12px Arial,Helvetica,Tahoma,Verdana,Sans-Serif; + float: left; + margin-top: 6px; + border: 1px solid #a6a6a6; + border-bottom-color: #979797; + background: #eeeeee; + border-radius: 3px; +} +#website-top-edit li.oe_snippet_editorbar > * { + display: inline-block; + height: 22px; + padding: 4px 6px; + outline: 0; + border: 0; +} +#website-top-edit li.oe_snippet_editorbar a.button .icon { + cursor: inherit; + background-repeat: no-repeat; + margin-top: 1px; + width: 16px; + height: 16px; + display: inline-block; +} \ No newline at end of file diff --git a/addons/website/static/src/js/website.editor.js b/addons/website/static/src/js/website.editor.js index a98376ae30f..8056998eef9 100644 --- a/addons/website/static/src/js/website.editor.js +++ b/addons/website/static/src/js/website.editor.js @@ -275,6 +275,11 @@ // editor.ui.items -> possible commands &al // editor.applyStyle(new CKEDITOR.style({element: "span",styles: {color: "#(color)"},overrides: [{element: "font",attributes: {color: null}}]}, {color: '#ff0000'})); + init: function (EditorBar) { + this.EditorBar = EditorBar; + this._super.apply(this, arguments); + }, + start_edition: function ($elements) { var self = this; $elements @@ -284,6 +289,7 @@ var $node = $(node); var editor = CKEDITOR.inline(this, self._config()); editor.on('instanceReady', function () { + self.trigger('instanceReady'); observer.observe(node, OBSERVER_CONFIG); }); $node.one('content_changed', function () { @@ -511,7 +517,7 @@ this.$('input.pages').val($target.text()).change(); // No #dropdown('close'), and using #dropdown('toggle') sur // #closest('.dropdown') makes the dropdown not work correctly - $target.closest('.open').removeClass('open') + $target.closest('.open').removeClass('open'); }, /** * CKEDITOR.plugins.link.getSelectedLink ignores the editor's root, diff --git a/addons/website/static/src/js/website.js b/addons/website/static/src/js/website.js index 1be97c02df0..00ee14aac00 100644 --- a/addons/website/static/src/js/website.js +++ b/addons/website/static/src/js/website.js @@ -31,35 +31,6 @@ return def; }; - website.mutations = { - darken: function($el){ - var $parent = $el.parent(); - if($parent.hasClass('dark')){ - $parent.replaceWith($el); - }else{ - $el.replaceWith($("
").append($el.clone())); - } - }, - vomify: function($el){ - var hue=0; - var beat = false; - var a = setInterval(function(){ - $el.css({'-webkit-filter':'hue-rotate('+hue+'deg)'}); hue += 5; - }, 10); - setTimeout(function(){ - clearInterval(a); - setInterval(function(){ - var filter = 'hue-rotate('+hue+'deg)'+ (beat ? ' invert()' : ''); - $(document.documentElement).css({'-webkit-filter': filter}); hue += 5; - if(hue % 35 === 0){ - beat = !beat; - } - }, 10); - },5000); - $('').appendTo($el); - }, - }; - var all_ready = null; var dom_ready = website.dom_ready = $.Deferred(); diff --git a/addons/website/static/src/js/website.snippets.js b/addons/website/static/src/js/website.snippets.js index 5ebf7aecc8d..fa806f16f88 100644 --- a/addons/website/static/src/js/website.snippets.js +++ b/addons/website/static/src/js/website.snippets.js @@ -2,98 +2,135 @@ 'use strict'; var website = openerp.website; + 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]'); - window.snippets = this.snippets = new website.Snippets(); - this.snippets.appendTo($(document.body)); + }.bind(this)); }, + edit: function () { + var res = this._super.apply(this, arguments); + var self = this; + var instanceReady = false; + this.rte.on('instanceReady', this, function () { + clearTimeout(instanceReady); + instanceReady = setTimeout(function () { + self.activate_building_block_manipulators(); + self.activate_snippet_click_editor(); + }, 0); + + }); + return res; + }, + + activate_building_block_manipulators: function () { + window.snippets = this.snippets = new website.snippet.BuildingBlock(this); + this.snippets.appendTo($(document.body)); + this.snippets.activate_snippet_manipulators(); + }, snippet: function (ev) { this.snippets.toggle(); }, - }); - - website.RTE.include({ - start_edition: function ($elements) { - this.snippet_carousel(); - return this._super($elements); - }, - // TODO clean - snippet_carousel: function () { + activate_snippet_click_editor: function () { var self = this; - $('.carousel').each(function () { - var $carousel = $(this); - var $options = $('.js_carousel_options', $carousel); - $options.on('click', '.label', function (e) { - e.preventDefault(); - var $button = $(e.currentTarget); - var $c = $button.parents(".carousel:first"); - var $carousel_inner = $c.find('.carousel-inner'); + var $snipped_id = false; + var snipped_event_flag = false; + $("body").on('click', "[data-snippet-id]", function (event) { + if (snipped_event_flag) { + return; + } - if($button.hasClass("js_add")) { - var cycle = $carousel_inner.find('.item').size(); - $carousel_inner.append(openerp.qweb.render('website.carousel')); - $c.carousel(cycle); + snipped_event_flag = true; + setTimeout(function () {snipped_event_flag = false;}, 0); + + if ($snipped_id && $snipped_id.get(0) == event.currentTarget) { + return; } - else if ($carousel_inner.find('.item').size() > 1) { - $carousel_inner - .find('.item.active').remove().end() - .find('.item:first').addClass('active'); - $c.carousel(0); - self.trigger('change', self, null); + + self.snippet_blur($snipped_id); + + $snipped_id = $(event.currentTarget); + + if (typeof $snipped_id.data("snippet-editor") === 'undefined') { + $snipped_id.data("snippet-editor", new (website.snippet.editorRegistry[$snipped_id.data("snippet-id")] || website.snippet.editorRegistry.box)(self, $snipped_id)); + } + self.snippet_focus($snipped_id); + }); + $("body > :not(:has(#website-top-view))").on('click', function (ev) { + if (!snipped_event_flag && $snipped_id) { + self.snippet_blur($snipped_id); + $snipped_id = false; } }); - $options.on('change', 'select[name="carousel-background"]', function () { - $('.carousel-inner .item.active', $carousel).css('background-image', 'url(' + $(this).val() + ')'); - $(this).val(""); - }); - $options.on('change', 'select[name="carousel-style"]', function () { - var $container = $('.carousel-inner .item.active .container', $carousel); - $('.content_image', $container).remove(); - switch ($(this).val()) { - case 'no_image': - $('.content', $container).attr("class", "content"); - break; - case 'image_left': - $('.content', $container).attr("class", "content col-md-6") - .before('
'); - break; - case 'image_right': - $('.content', $container).attr("class", "content col-md-6") - .after('
'); - break; - } - $(this).val(""); - }); - $options.show(); - }); + }, + snippet_blur: function ($snipped_id) { + if ($snipped_id) { + if ($snipped_id.data("snippet-editor")) { + $snipped_id.data("snippet-editor").onBlur(); + } + if ($snipped_id.data("snippet-view")) { + $snipped_id.data("snippet-view").onBlurEdit(); + } + } + }, + snippet_focus: function ($snipped_id) { + if ($snipped_id) { + if ($snipped_id.data("snippet-view")) { + $snipped_id.data("snippet-view").onFocusEdit(); + } + if ($snipped_id.data("snippet-editor")) { + $snipped_id.data("snippet-editor").onFocus(); + } + } }, }); /* ----- SNIPPET SELECTOR ---- */ - website.Snippets = openerp.Widget.extend({ + + website.snippet = {}; + + // puts $el at the same absolute position as $target + website.snippet.cover_target = function cover_target($el, $target){ + $el.css({ + 'position': 'absolute', + 'width': $target.outerWidth(), + 'height': $target.outerHeight(), + }); + $el.css($target.offset()); + } + + website.snippet.BuildingBlock = openerp.Widget.extend({ template: 'website.snippets', - init: function () { + init: function (parent) { + this.parent = parent; this._super.apply(this, arguments); + if(!$('#oe_manipulators').length){ + $("
").appendTo('body'); + } }, start: function() { var self = this; - $.ajax({ - type: "GET", - url: "/page/website.snippets", - dataType: "text", - success: function(snippets){ - self.$el.html(snippets); - self.start_snippets(); - }, + var snippets_template = []; + _.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.append($snippet); + self.make_snippet_draggable($snippet); + } + } }); + this.bind_selected_manipulator(); + }, path_eval: function(path){ var obj = window; @@ -104,26 +141,40 @@ return obj; }, - // setup widget and drag and drop - start_snippets: function(){ + bind_selected_manipulator: function () { + + var $selected_target = null; + $("body").mouseover(function (event){ + var $target = $(event.srcElement).parents("[data-snippet-id]:first"); + if($target.length && $selected_target != $target){ + if($selected_target){ + $selected_target.data('manipulator').removeClass('oe_selected'); + } + $selected_target = $target; + $target.data('manipulator').addClass('oe_selected'); + } + }); + }, + + // activate drag and drop for the snippets in the snippet toolbar + make_snippet_draggable: function($snippet){ var self = this; - this.$('.oe_snippet').draggable({ + $snippet.draggable({ helper: 'clone', zIndex: '1000', appendTo: 'body', start: function(){ - var snippet = $(this); - var action = snippet.data('action'); + var action = $snippet.data('action'); self.deactivate_snippet_manipulators(); if( action === 'insert'){ self.activate_insertion_zones({ - siblings: snippet.data('selector-siblings'), - childs: snippet.data('selector-childs') + siblings: $snippet.data('selector-siblings'), + childs: $snippet.data('selector-childs') }); }else if( action === 'mutate' ){ - self.activate_overlay_zones(snippet.data('selector')); + self.activate_overlay_zones($snippet.data('selector')); } $('.oe_drop_zone').droppable({ @@ -137,12 +188,25 @@ $(this).removeClass("oe_hover"); }, drop: function(){ - if( action === 'insert' ){ - $(".oe_drop_zone.oe_hover") - .replaceWith(snippet.find('.oe_snippet_body').clone()) - .removeClass('oe_snippet_body'); - }else if( action === 'mutate' ){ - self.path_eval(snippet.data('action-function'))( $(".oe_drop_zone.oe_hover").data('target') ); + var snipped_id = $snippet.data('snippet-id'); + if($snippet.find('.oe_snippet_body').size()){ + var $toInsert = $snippet.find('.oe_snippet_body').clone(); + $toInsert.removeClass('oe_snippet_body'); + $toInsert.addClass('oe_snippet_instance'); + $toInsert.attr('data-snippet-id', snipped_id); + $(".oe_drop_zone.oe_hover").replaceWith($toInsert); + var $target = $toInsert; + + self.deactivate_snippet_manipulators(); + self.activate_snippet_manipulators(); + } else { + var $target = $(".oe_drop_zone.oe_hover").data('target'); + } + + if (website.snippet.editorRegistry[snipped_id]) { + var snippet = new website.snippet.editorRegistry[snipped_id](this.parent, $target); + snippet.build_snippet($target); + $target.click(); } }, }); @@ -152,8 +216,38 @@ self.activate_snippet_manipulators(); }, }); - }, + + // return the original snippet in the editor bar from a snippet id (string) + get_snippet_from_id: function(id){ + return $('.oe_snippet').filter(function(){ + 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({ + helper: 'clone', + zIndex: '1000', + appendTo: 'body', + start: function(){ + var action = $snippet.data('action'); + if(action === 'insert'){ + + self.deactivate_snippet_manipulators(); + self.activate_insertion_zones({ + siblings: $snippet.data('selector-siblings'), + child: $snippet.data('selector-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 // in case the selected elements have children themselves, dropzones will be interleaved @@ -161,25 +255,23 @@ // selector.siblings -> will insert drop zones after and before selected elements activate_insertion_zones: function(selector){ var self = this; - var i, len, $zones; var child_selector = selector.childs || ''; var sibling_selector = selector.siblings || ''; var zone_template = "
"; - var $drop_zone = $('.oe_drop_zone'); - $drop_zone.remove(); + $('.oe_drop_zone').remove(); if(child_selector){ - $zones = $(child_selector); - for(i = 0, len = $zones.length; i < len; i++ ){ + var $zones = $(child_selector); + for( var i = 0, len = $zones.length; i < len; i++ ){ $zones.eq(i).find('> *:not(.oe_drop_zone)').after(zone_template); $zones.eq(i).prepend(zone_template); } } if(sibling_selector){ - $zones = $(sibling_selector); - for(i = 0, len = $zones.length; i < len; i++ ){ + var $zones = $(sibling_selector); + for( var i = 0, len = $zones.length; i < len; i++ ){ if($zones.eq(i).prev('.oe_drop_zone').length === 0){ $zones.eq(i).before(zone_template); } @@ -191,12 +283,12 @@ // Cleaning up unnecessary zones $('.oe_snippets .oe_drop_zone').remove(); // no zone in the snippet selector ... - $('#website-top-view').find('.oe_drop_zone').remove(); // no zone in the top bars ... - $('#website-top-edit').find('.oe_drop_zone').remove(); + $('#website-top-view .oe_drop_zone').remove(); // no zone in the top bars ... + $('#website-top-edit .oe_drop_zone').remove(); var count; do { count = 0; - $zones = $('.oe_drop_zone + .oe_drop_zone'); // no two consecutive zones + var $zones = $('.oe_drop_zone + .oe_drop_zone'); // no two consecutive zones count += $zones.length; $zones.remove(); @@ -206,23 +298,25 @@ }while(count > 0); // Cleaning up zones placed between floating or inline elements. We do not like these kind of zones. - $zones = $drop_zone; - for(i = 0, len = $zones.length; i < len; i++ ){ + var $zones = $('.oe_drop_zone'); + for( var i = 0, len = $zones.length; i < len; i++ ){ var zone = $zones.eq(i); var prev = zone.prev(); var next = zone.next(); - var float_prev = prev.css('float') || 'none'; - var float_next = next.css('float') || 'none'; - var disp_prev = prev.css('display') || null; - var disp_next = next.css('display') || null; + var float_prev = zone.prev().css('float') || 'none'; + var float_next = zone.next().css('float') || 'none'; + var disp_prev = zone.prev().css('display') || null; + var disp_next = zone.next().css('display') || null; if( (float_prev === 'left' || float_prev === 'right') && (float_next === 'left' || float_next === 'right') ){ zone.remove(); + continue; }else if( !( disp_prev === null || disp_next === null || disp_prev === 'block' || disp_next === 'block' )){ zone.remove(); + continue; } } }, @@ -230,9 +324,10 @@ $('.oe_drop_zone').remove(); }, + // generate drop zones covering the elements selected by the selector activate_overlay_zones: function(selector){ var $targets = $(selector); - + function is_visible($el){ return $el.css('display') != 'none' && $el.css('opacity') != '0' @@ -247,82 +342,43 @@ var parents = $(this).parents().filter(function(){ return !is_visible($(this)); }); return parents.length === 0; }); - + var zone_template = "
"; $('.oe_drop_zone').remove(); for(var i = 0, len = $targets.length; i < len; i++){ var $target = $targets.eq(i); var $zone = $(zone_template); - this.cover_target($zone,$target); - $zone.appendTo('body'); + website.snippet.cover_target($zone,$target); + $zone.appendTo('#oe_manipulators'); $zone.data('target',$target); } }, - cover_target: function($el, $target){ - $el.css({ - 'position': 'absolute', - 'width': $target.outerWidth(), - 'height': $target.outerHeight(), - }); - $el.css($target.offset()); - }, + + // activates the manipulator boxes (with resizing handles) for all snippets activate_snippet_manipulators: function(){ var self = this; - this.activate_overlay_zones('#wrap .container'); - var $snippets = $('.oe_drop_zone'); + // we generate overlay drop zones only to get an idea of where the snippet are, the drop + // zones are replaced by manipulators + this.activate_overlay_zones('#wrap [data-snippet-id]'); - for(var i = 0, len = $snippets.length; i < len; i++){ - var $snippet = $snippets.eq(i); + $('.oe_drop_zone').each(function(){ + + var $zone = $(this); + var $snippet = $zone.data('target'); var $manipulator = $(openerp.qweb.render('website.snippet_manipulator')); - $manipulator.css({ - 'top': $snippet.css('top'), - 'left': $snippet.css('left'), - 'width': $snippet.css('width'), - 'height': $snippet.css('height'), - }); - $manipulator.data('target',$snippet.data('target')); - $manipulator.appendTo('body'); - $snippet.remove(); - $manipulator.find('.oe_handle').mousedown(function(event){ - var $handle = $(this); - var $manipulator = $handle.parent(); - var $snippet = $manipulator.data('target'); - var x = event.pageX; - var y = event.pageY; - - var pt = $snippet.css('padding-top'); - var pb = $snippet.css('padding-bottom'); - pt = Number(pt.slice(0, -2)) || 0; //FIXME something cleaner to remove 'px' - pb = Number(pb.slice(0, -2)) || 0; - - $manipulator.addClass('oe_hover'); - event.preventDefault(); - - $(document.body).on({ - mousemove: function(event){ - var dx = event.pageX - x; - var dy = event.pageY - y; - event.preventDefault(); - if($handle.hasClass('n') || $handle.hasClass('nw') || $handle.hasClass('ne')){ - $snippet.css('padding-top',pt-dy+'px'); - self.cover_target($manipulator,$snippet); - }else if($handle.hasClass('s') || $handle.hasClass('sw') || $handle.hasClass('se')){ - - $snippet.css('padding-bottom',pb+dy+'px'); - self.cover_target($manipulator,$snippet); - } - }, - mouseup: function(){ - $body.off('mouseup mousemove'); - self.deactivate_snippet_manipulators(); - self.activate_snippet_manipulators(); - } - }); + website.snippet.cover_target($manipulator, $zone); + $manipulator.data('target',$snippet); + $snippet.data('manipulator',$manipulator); + $manipulator.appendTo('#oe_manipulators'); + $zone.remove(); + $snippet.off("resize").on("resize", function () { + self.deactivate_snippet_manipulators(); + self.activate_snippet_manipulators(); }); - } + }); }, deactivate_snippet_manipulators: function(){ $('.oe_snippet_manipulator').remove(); @@ -330,11 +386,312 @@ toggle: function(){ if(this.$el.hasClass('hide')){ this.$el.removeClass('hide'); - this.activate_snippet_manipulators(); + //this.activate_snippet_manipulators(); }else{ this.$el.addClass('hide'); - this.deactivate_snippet_manipulators(); + //this.deactivate_snippet_manipulators(); } }, }); -})(); + + + website.snippet.animationRegistry = {}; + website.snippet.Animation = openerp.Class.extend({ + $: function () { + return this.$el.find.apply(this.$el, arguments); + }, + init: function (dom) { + this.$el = $(dom); + this._super.apply(this, arguments); + }, + /* onFocusEdit + * if they are an editor for this snippet-id + * Called before onFocus of snippet editor + */ + onFocusEdit : function () {}, + + /* onBlurEdit + * if they are an editor for this snippet-id + * Called after onBlur of snippet editor + */ + onBlurEdit : function () {}, + + /* getOptions + * get the options saved in the html view + */ + getOptions: function () { + var options = this.$el.data("snippet-options"); + return options ? JSON.parse(options) : undefined; + }, + }); + + + $(document).ready(function () { + $("[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.Widget.extend({ + init: function (parent, dom) { + this.$target = $(dom); + this.parent = parent; + this._super.apply(this, arguments); + this.renderElement(); + this.start(); + }, + + renderElement: function() { + var $el; + if (this.template) { + $el = $(openerp.qweb.render(this.template, {widget: this}).trim()); + this.$editor = $el.find(".oe_snippet_editorbar"); + this.$thumbnail = $el.find(".oe_snippet_thumbnail"); + this.$body = $el.find(".oe_snippet_body"); + } else { + $el = this._make_descriptive(); + } + this.replaceElement($el); + }, + + // create the snippet into the view + build_snippet: function () { + + }, + + /* onFocus + * called when the user click inside the snippet dom + */ + onFocus : function () { + if(this.$editor) this.$editor.prependTo(this.parent.$('#website-top-edit .nav.pull-right')); + }, + + /* onFocus + * called when the user click outide the snippet dom + */ + onBlur : function () { + if(this.$editor) this.$editor.detach(); + }, + + /* setOptions + * saved the options in the html view + */ + setOptions: function (options) { + $target.attr("data-snippet-options", JSON.stringify(options)); + }, + + /* getOptions + * get the options saved in the html view + */ + getOptions: function () { + var options = this.$target.data("snippet-options"); + return options ? JSON.parse(options) : undefined; + }, + }); + + + website.snippet.editorRegistry.box = website.snippet.Editor.extend({ + onFocus : function () { + var self = this; + var $box = $(openerp.qweb.render("website.snippets.box")); + + $box.find(".oe_snippet_editorbar").prependTo(this.parent.$('#website-top-edit .nav.pull-right')); + + this.$target.data('manipulator').append($box.find(".oe_handles").html()).addClass('oe_active'); + + function padding_margin_cover ($manipulator, $snippet) { + var height = parseInt($snippet.height() || 0); + var width = parseInt($snippet.width() || 0); + + var pcss = { + top: parseInt($snippet.css('padding-top')) + 'px', + bottom: parseInt($snippet.css('padding-bottom')) + 'px', + left: parseInt($snippet.css('padding-left')) + 'px', + right: parseInt($snippet.css('padding-right')) + 'px', + }; + var $padding = $manipulator.find(".oe_boxsize").css(pcss); + + var mcss = { + top: -parseInt($snippet.css('margin-top')) + 'px', + bottom: -parseInt($snippet.css('margin-bottom')) + 'px', + left: -parseInt($snippet.css('margin-left')) + 'px', + right: -parseInt($snippet.css('margin-right')) + 'px', + }; + var $margin = $manipulator.find(".oe_margin").css(mcss); + } + padding_margin_cover( this.$target.data('manipulator'), this.$target); + + this.$target.data('manipulator').find(".oe_handle").on('mousedown', function (event){ + event.preventDefault(); + + var $handle = $(this); + var $manipulator = self.$target.data('manipulator'); + var $snippet = self.$target; + + var x = event.pageX; + var y = event.pageY; + + var padding=[parseInt($snippet.css('padding-top') || 0), + parseInt($snippet.css('padding-bottom') || 0), + parseInt($snippet.css('padding-left') || 0), + parseInt($snippet.css('padding-right') || 0)]; + + $manipulator.addClass('oe_hover'); + + var body_mousemove = function (event){ + event.preventDefault(); + var dx = event.pageX - x; + var dy = event.pageY - y; + + if($handle.hasClass('n') || $handle.hasClass('nw') || $handle.hasClass('ne')){ + $snippet.css('padding-top', (padding[0]+dy)+'px'); + } + if($handle.hasClass('s') || $handle.hasClass('sw') || $handle.hasClass('se')){ + $snippet.css('padding-bottom',(padding[1]-dy)+'px'); + } + if($handle.hasClass('w') || $handle.hasClass('sw') || $handle.hasClass('nw')){ + $snippet.css('padding-left',(padding[2]+dx)+'px'); + } + if($handle.hasClass('e') || $handle.hasClass('se') || $handle.hasClass('ne')){ + $snippet.css('padding-right',(padding[3]-dx)+'px'); + } + website.snippet.cover_target($manipulator, $snippet); + padding_margin_cover($manipulator, $snippet); + }; + $('body').mousemove(body_mousemove); + + var body_mouseup = function(){ + $('body').unbind('mousemove', body_mousemove); + $('body').unbind('mouseup', body_mouseup); + $snippet.trigger("resize"); + self.onBlur(); + self.onFocus(); + }; + $('body').mouseup(body_mouseup); + }); + this._super(); + }, + onBlur : function () { + this._super(); + this.$target.data('manipulator') + .removeClass('oe_active') + .empty(); + this.parent.$('#website-top-edit .nav.pull-right > .box_resize').remove(); + }, + }); + + website.snippet.editorRegistry.carousel = website.snippet.editorRegistry.box.extend({ + template : "website.snippets.carousel", + build_snippet: function($target) { + var id = "myCarousel" + $("body .carousel").size(); + $target.attr("id", id); + $target.find(".carousel-control").attr("href", "#"+id); + }, + start : function () { + var self = this; + + this.$editor.find(".js_add").on('click', this.on_add); + this.$editor.find(".js_remove").on('click', this.on_remove); + + var bg = this.$target.find('.carousel-inner .item.active').css('background-image').replace(/url\((.*)\)/g, '\$1'); + 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); + + this.$editor.find('select[name="carousel-background"]').on('change', function () { + self.$target.find('.carousel-inner .item.active').css('background-image', 'url(' + $(this).val() + ')'); + }); + + 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'; + 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); + this.$target.trigger("resize"); + }, + 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.$target.trigger("resize"); + } + }, + 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; + } + + $('.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('
'); + break; + case 'image_right': + $('.content', $container).attr("class", "content col-md-6") + .after('
'); + break; + } + }, + }); + + 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{ + $target.replaceWith($("
").append($target.clone())); + } + } + }); + + website.snippet.editorRegistry.vomify = website.snippet.Editor.extend({ + build_snippet: function($target) { + var hue=0; + var beat = false; + var a = setInterval(function(){ + $target.css({'-webkit-filter':'hue-rotate('+hue+'deg)'}); hue += 5; + }, 10); + setTimeout(function(){ + clearInterval(a); + setInterval(function(){ + var filter = 'hue-rotate('+hue+'deg)'+ (beat ? ' invert()' : ''); + $(document.documentElement).css({'-webkit-filter': filter}); hue += 5; + if(hue % 35 === 0){ + beat = !beat; + } + }, 10); + },5000); + $('').appendTo($target); + } + }); + +})(); \ No newline at end of file diff --git a/addons/website/static/src/xml/website.snippets.xml b/addons/website/static/src/xml/website.snippets.xml new file mode 100644 index 00000000000..41b955cffbf --- /dev/null +++ b/addons/website/static/src/xml/website.snippets.xml @@ -0,0 +1,177 @@ + + + + + + +
+
+
+ + +
+
+ + + +
+ + +
  • + + +
  • + + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + +
    + + +
  • + + + + +
  • + + +
    carousel
    + + + + + +
    +
    +
    +

    Your New Banner Slide

    +

    With another convincing subtitle

    + Contact us +
    +
    +
    +
    + +
    +
    Darken
    +
    + +
    +
    Surprise!
    +
    + +
    +
    Spacer
    +
    +
    + +
    +
    + Main Title +
    +
    +
    +
    +

    Welcome To Your New Homepage,

    +

    where everything can be customized

    +
    +
    +
    +
    + +
    +
    +
    +
    +

    Ut enim ad minim veniam

    +
    +
    +
    +
    + +

    Cillum Dolore

    +

    Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod + tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, + quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo + consequat.

    +
    +
    + +

    Mollit Anim

    +

    Duis aute irure dolor in reprehenderit in voluptate velit esse cillum + dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non + proident, sunt in culpa qui officia deserunt mollit anim id est laborum

    +
    +
    + +

    Nemo Enim Ipsam

    +

    Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium + doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore + veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim + ipsam voluptatem quia voluptas

    +
    +
    +
    +
    + +
    +
    +
    +
    + +
    +
    +

    Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod + tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, + quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo + consequat.

    +

    Duis aute irure dolor in reprehenderit in voluptate velit esse cillum + dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non + proident, sunt in culpa qui officia deserunt mollit anim id est laborum

    + +
    +
    +
    +
    + +
    diff --git a/addons/website/static/src/xml/website.xml b/addons/website/static/src/xml/website.xml index 5b5018e1b37..7ddd483a6fb 100644 --- a/addons/website/static/src/xml/website.xml +++ b/addons/website/static/src/xml/website.xml @@ -57,34 +57,4 @@ - -
    -
    -
    -

    Your New Banner Slide

    -

    With another convincing subtitle

    - Contact us -
    -
    -
    -
    - - -
    -
    -
    - - -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    - diff --git a/addons/website/views/views.xml b/addons/website/views/views.xml index 90de96e1541..14db86e995f 100644 --- a/addons/website/views/views.xml +++ b/addons/website/views/views.xml @@ -157,27 +157,11 @@ - - -