diff --git a/addons/website/static/src/css/editor.css b/addons/website/static/src/css/editor.css index 7cb2dc08a4f..60a7906f429 100644 --- a/addons/website/static/src/css/editor.css +++ b/addons/website/static/src/css/editor.css @@ -142,7 +142,7 @@ border-top: dashed 2px rgba(116, 255, 161, 0.72); } -.oe_drop_zone.oe_mutate { +.oe_drop_zone.oe_overlay { position: absolute; background: rgba(153, 0, 255, 0.17); border-radius: 3px; @@ -157,6 +157,63 @@ z-index: 99; } +/* ---- SNIPPET MANIPULATOR ---- */ +.oe_snippet_manipulator { + display: block; + position: absolute; + background: rgba(153, 0, 255, 0.1); + border-radius: 3px; + border: solid 1px rgba(153, 0, 255, 0.5); + opacity: 0; + transition: opacity 100ms linear; +} +.oe_snippet_manipulator > .oe_handle { + display: none; +} +.oe_snippet_manipulator:hover, .oe_snippet_manipulator.oe_hover { + opacity: 1; +} +.oe_snippet_manipulator:hover > .oe_handle, .oe_snippet_manipulator.oe_hover > .oe_handle { + display: block; +} + +.oe_handle { + position: absolute; + top: 50%; + left: 50%; + display: block; + background: white; + border: solid 1px rgba(153, 0, 255, 0.5); + box-sizing: border-box; + border-radius: 2px; + width: 16px; + height: 16px; + margin: -8px; + cursor: move; + -webkit-transition: background 100ms linear; +} +.oe_handle:hover { + background: #9900ff; +} + +.oe_handle.nw, .oe_handle.n, .oe_handle.ne { + top: 0px; +} + +.oe_handle.ne, .oe_handle.e, .oe_handle.se { + left: auto; + right: 0px; +} + +.oe_handle.sw, .oe_handle.s, .oe_handle.se { + top: auto; + bottom: 0px; +} + +.oe_handle.nw, .oe_handle.w, .oe_handle.sw { + left: 0px; +} + /* ---- MOBILE PREVIEW ---- */ .oe_stop_scrolling { height: 100%; diff --git a/addons/website/static/src/css/editor.sass b/addons/website/static/src/css/editor.sass index 45078e12b0b..dade66519a8 100644 --- a/addons/website/static/src/css/editor.sass +++ b/addons/website/static/src/css/editor.sass @@ -129,7 +129,7 @@ &.oe_hover:before border-top: dashed 2px rgba(116, 255, 161, 0.72) -.oe_drop_zone.oe_mutate +.oe_drop_zone.oe_overlay position: absolute background: rgba(153, 0, 255, 0.17) border-radius: 3px @@ -141,6 +141,51 @@ background: rgba(0, 255, 133, 0.22) z-index: 99 +/* ---- SNIPPET MANIPULATOR ---- */ + +.oe_snippet_manipulator + display: block + position: absolute + background: rgba(153, 0, 255, 0.1) + border-radius: 3px + border: solid 1px rgba(153, 0, 255, 0.5) + opacity: 0 + transition: opacity 100ms linear + & > .oe_handle + display: none + &:hover,&.oe_hover + opacity: 1 + & > .oe_handle + display: block + +.oe_handle + position: absolute + top: 50% + left: 50% + display: block + background: rgba(255, 255, 255, 1) + border: solid 1px rgba(153, 0, 255, 0.5) + box-sizing: border-box + border-radius: 2px + width: 16px + height: 16px + margin: -8px + cursor: move + -webkit-transition: background 100ms linear + &:hover + background: rgb(153, 0, 255) + +.oe_handle.nw,.oe_handle.n,.oe_handle.ne + top: 0px +.oe_handle.ne,.oe_handle.e,.oe_handle.se + left: auto + right: 0px +.oe_handle.sw,.oe_handle.s,.oe_handle.se + top: auto + bottom: 0px +.oe_handle.nw,.oe_handle.w,.oe_handle.sw + left: 0px + /* ---- MOBILE PREVIEW ---- */ .oe_stop_scrolling diff --git a/addons/website/static/src/css/website.css b/addons/website/static/src/css/website.css index 2ba763f402e..4567384975d 100644 --- a/addons/website/static/src/css/website.css +++ b/addons/website/static/src/css/website.css @@ -161,6 +161,4 @@ header.navbar-fixed-top { .dark { background: #eff8f8; - padding-top: 32px; - padding-bottom: 32px; } diff --git a/addons/website/static/src/css/website.sass b/addons/website/static/src/css/website.sass index 0440a71624f..8b885c548d1 100644 --- a/addons/website/static/src/css/website.sass +++ b/addons/website/static/src/css/website.sass @@ -121,7 +121,5 @@ header.navbar-fixed-top .dark background: rgb(239, 248, 248) - padding-top: 32px - padding-bottom: 32px diff --git a/addons/website/static/src/js/website.js b/addons/website/static/src/js/website.js index 0230a657784..c71126816c1 100644 --- a/addons/website/static/src/js/website.js +++ b/addons/website/static/src/js/website.js @@ -368,7 +368,7 @@ start_snippets: function(){ var self = this; - this.$('.oe_snippe').draggable({ + this.$('.oe_snippet').draggable({ helper: 'clone', zIndex: '1000', appendTo: 'body', @@ -376,13 +376,14 @@ var snippet = $(this); var action = snippet.data('action'); + self.deactivate_snippet_manipulators(); if( action === 'insert'){ - self.activate_drop_zones({ + self.activate_insertion_zones({ siblings: snippet.data('selector-siblings'), childs: snippet.data('selector-childs') }); }else if( action === 'mutate' ){ - self.activate_hover_zones(snippet.data('selector')); + self.activate_overlay_zones(snippet.data('selector')); } $('.oe_drop_zone').droppable({ @@ -407,17 +408,18 @@ }); }, stop: function(){ - self.deactivate_drop_zones(); + self.deactivate_zones(); + self.activate_snippet_manipulators(); }, }); }, - // A generic drop zone generator. two css selectors can be provided + // 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 // with them. // selector.siblings -> will insert drop zones after and before selected elements - activate_drop_zones: function(selector){ + activate_insertion_zones: function(selector){ var self = this; var child_selector = selector.childs || ''; var sibling_selector = selector.siblings || ''; @@ -484,10 +486,11 @@ } } }, - deactivate_drop_zones: function(){ + deactivate_zones: function(){ $('.oe_drop_zone').remove(); }, - activate_hover_zones: function(selector){ + + activate_overlay_zones: function(selector){ var $targets = $(selector); function is_visible($el){ @@ -505,26 +508,91 @@ return parents.length === 0; }); - var zone_template = "
"; + 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); - $zone.css({ - 'width': $target.outerWidth(), - 'height': $target.outerHeight(), - }); - $zone.css($target.offset()); + this.cover_target($zone,$target); $zone.appendTo('body'); $zone.data('target',$target); } }, + cover_target: function($el, $target){ + $el.css({ + 'position': 'absolute', + 'width': $target.outerWidth(), + 'height': $target.outerHeight(), + }); + $el.css($target.offset()); + }, + activate_snippet_manipulators: function(){ + var self = this; + this.activate_overlay_zones('#wrap .container'); + var $snippets = $('.oe_drop_zone'); + + for(var i = 0, len = $snippets.length; i < len; i++){ + var $snippet = $snippets.eq(i); + 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,pt.length - 2)) || 0; //FIXME something cleaner to remove 'px' + pb = Number(pb.slice(0,pb.length - 2)) || 0; + + $manipulator.addClass('oe_hover'); + event.preventDefault(); + + $('body').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); + } + }); + $('body').mouseup(function(){ + $('body').unbind('mousemove'); + $('body').unbind('mouseup'); + self.deactivate_snippet_manipulators(); + self.activate_snippet_manipulators(); + }); + }); + + } + }, + deactivate_snippet_manipulators: function(){ + $('.oe_snippet_manipulator').remove(); + }, toggle: function(){ if(this.$el.hasClass('oe_hidden')){ this.$el.removeClass('oe_hidden'); + this.activate_snippet_manipulators(); }else{ this.$el.addClass('oe_hidden'); + this.deactivate_snippet_manipulators(); } }, }); diff --git a/addons/website/static/src/xml/website.xml b/addons/website/static/src/xml/website.xml index e58a72c8f25..5e83471976e 100644 --- a/addons/website/static/src/xml/website.xml +++ b/addons/website/static/src/xml/website.xml @@ -67,4 +67,17 @@ + +
+
+
+
+
+
+
+
+
+
+
+ diff --git a/addons/website/views/views.xml b/addons/website/views/views.xml index b63eedd890d..b9cbe035d3d 100644 --- a/addons/website/views/views.xml +++ b/addons/website/views/views.xml @@ -401,20 +401,20 @@