diff --git a/addons/website/static/src/css/editor.css b/addons/website/static/src/css/editor.css index 8f810f328d6..8a20e94bec0 100644 --- a/addons/website/static/src/css/editor.css +++ b/addons/website/static/src/css/editor.css @@ -58,6 +58,7 @@ display: none; } +/* ---- SNIPPET EDITOR ---- */ .oe_snippets { position: fixed; left: 0px; @@ -68,6 +69,7 @@ background: #282828; box-shadow: 0px 10px 10px -10px black inset; overflow-y: auto; + z-index: 100; } .oe_snippet { @@ -84,6 +86,7 @@ overflow: hidden; -webkit-user-select: none; user-select: none; + cursor: move; } .oe_snippet .oe_snippet_thumbnail.oe_label { text-align: center; @@ -107,53 +110,111 @@ -webkit-transform: scale(0.095); } -.oe_drop_zone { +/* ---- SNIPPETS DROP ZONES ---- */ +.oe_drop_zone.oe_insert { display: block; - background: rgba(153, 0, 255, 0.17); - border-radius: 3px; height: 32px; margin: -16px 0px; -webkit-transition: margin 250ms linear; } -.oe_drop_zone:first-child:not(:last-child) { +.oe_drop_zone.oe_insert:first-child:not(:last-child) { margin-top: -8px; margin-bottom: -24px; } -.oe_drop_zone:last-child:not(:first-child) { +.oe_drop_zone.oe_insert:last-child:not(:first-child) { margin-top: -24px; margin-bottom: -8px; } -.oe_drop_zone.oe_hover { - background: rgba(0, 255, 133, 0.22); - z-index: 100000; -} -.oe_drop_zone:before { +.oe_drop_zone.oe_insert:before { content: ""; display: block; border-top: dashed 2px rgba(209, 178, 255, 0.72); position: relative; top: 16px; } -.oe_drop_zone:first-child:not(:last-child):before { +.oe_drop_zone.oe_insert:first-child:not(:last-child):before { top: 8px; } -.oe_drop_zone:last-child:not(:first-child):before { +.oe_drop_zone.oe_insert:last-child:not(:first-child):before { top: 24px; } -.oe_drop_zone.oe_hover:before { +.oe_drop_zone.oe_insert.oe_hover:before { border-top: dashed 2px rgba(116, 255, 161, 0.72); } -.oe_hover_zone { +.oe_drop_zone.oe_overlay { position: absolute; background: rgba(153, 0, 255, 0.17); border-radius: 3px; } -.oe_hover_zone.oe_hover { + +.oe_drop_zone { + background: rgba(153, 0, 255, 0.17); + border-radius: 3px; +} +.oe_drop_zone.oe_hover { background: rgba(0, 255, 133, 0.22); - z-index: 100000; + 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%; overflow: hidden; diff --git a/addons/website/static/src/css/editor.sass b/addons/website/static/src/css/editor.sass index 9ac81414eba..29621f95e4b 100644 --- a/addons/website/static/src/css/editor.sass +++ b/addons/website/static/src/css/editor.sass @@ -51,6 +51,8 @@ z-index: 1 display: none +/* ---- SNIPPET EDITOR ---- */ + .oe_snippets position: fixed left: 0px @@ -61,6 +63,7 @@ background: rgb(40,40,40) box-shadow: 0px 10px 10px -10px black inset overflow-y: auto + z-index: 100 .oe_snippet display: inline-block @@ -76,6 +79,7 @@ overflow: hidden -webkit-user-select: none user-select: none + cursor: move .oe_snippet_thumbnail.oe_label text-align: center @@ -98,10 +102,11 @@ -webkit-transform: scale(0.095) -.oe_drop_zone +/* ---- SNIPPETS DROP ZONES ---- */ + + +.oe_drop_zone.oe_insert display: block - background: rgba(153, 0, 255, 0.17) - border-radius: 3px height: 32px margin: -16px 0px -webkit-transition: margin 250ms linear @@ -111,9 +116,6 @@ &:last-child:not(:first-child) margin-top: -24px margin-bottom: -8px - &.oe_hover - background: rgba(0, 255, 133, 0.22) - z-index: 100000 &:before content: "" display: block @@ -127,14 +129,64 @@ &.oe_hover:before border-top: dashed 2px rgba(116, 255, 161, 0.72) -.oe_hover_zone +.oe_drop_zone.oe_overlay position: absolute background: rgba(153, 0, 255, 0.17) border-radius: 3px +.oe_drop_zone + background: rgba(153, 0, 255, 0.17) + border-radius: 3px &.oe_hover background: rgba(0, 255, 133, 0.22) - z-index: 100000 + 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 height: 100% 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 ed95981f1d4..c71126816c1 100644 --- a/addons/website/static/src/js/website.js +++ b/addons/website/static/src/js/website.js @@ -39,7 +39,7 @@ /* ----- TOP EDITOR BAR FOR ADMIN ---- */ website.EditorBar = openerp.Widget.extend({ - template: 'Website.EditorBar', + template: 'website.editorbar', events: { 'click button[data-action=edit]': 'edit', 'click button[data-action=save]': 'save', @@ -293,7 +293,7 @@ if($button.hasClass("js_add")) { var cycle = $c.find(".carousel-inner .item").size(); - $c.find(".carousel-inner").append(QWeb.render("Website.Snipped.carousel")); + $c.find(".carousel-inner").append(openerp.qweb.render("website.carousel")); $c.carousel(cycle); } else { @@ -368,16 +368,23 @@ start_snippets: function(){ var self = this; - this.$('.oe_snippet[data-action="insert"]').draggable({ + this.$('.oe_snippet').draggable({ helper: 'clone', + zIndex: '1000', appendTo: 'body', start: function(){ var snippet = $(this); + var action = snippet.data('action'); - self.activate_drop_zones({ - siblings: snippet.data('selector-siblings'), - childs: snippet.data('selector-childs') - }); + self.deactivate_snippet_manipulators(); + if( action === 'insert'){ + self.activate_insertion_zones({ + siblings: snippet.data('selector-siblings'), + childs: snippet.data('selector-childs') + }); + }else if( action === 'mutate' ){ + self.activate_overlay_zones(snippet.data('selector')); + } $('.oe_drop_zone').droppable({ over: function(){ @@ -390,53 +397,33 @@ $(this).removeClass("oe_hover"); }, drop: function(){ - $(".oe_drop_zone.oe_hover") - .replaceWith(snippet.find('.oe_snippet_body').clone()) - .removeClass('oe_snippet_body'); + 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') ); + } }, }); }, stop: function(){ - self.deactivate_drop_zones(); + self.deactivate_zones(); + self.activate_snippet_manipulators(); }, }); - this.$('.oe_snippet[data-action="mutate"]').draggable({ - helper: 'clone', - appendTo: 'body', - start: function(){ - var snippet = $(this); - - self.activate_hover_zones(snippet.data('selector')); - - $('.oe_hover_zone').droppable({ - over: function(){ - $(".oe_hover_zone.oe_hover").removeClass("oe_hover"); - $(this).addClass("oe_hover"); - }, - out: function(){ - $(this).removeClass("oe_hover"); - }, - drop: function(){ - self.path_eval(snippet.data('action-function'))( $(".oe_hover_zone.oe_hover").data('target') ); - }, - }); - }, - stop: function(){ - self.deactivate_hover_zones(); - }, - }); }, - // 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 || ''; - var zone_template = "
"; + var zone_template = "
"; $('.oe_drop_zone').remove(); @@ -499,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){ @@ -520,29 +508,91 @@ return parents.length === 0; }); - var zone_template = "
"; - $('.oe_hover_zone').remove(); + 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); } }, - deactivate_hover_zones: function(selector){ - $('.oe_hover_zone').remove(); + 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 f24498c5568..37a3bc453f3 100644 --- a/addons/website/static/src/xml/website.xml +++ b/addons/website/static/src/xml/website.xml @@ -2,75 +2,82 @@ - - + +