diff --git a/addons/website/static/src/css/editor.css b/addons/website/static/src/css/editor.css index bd68855d6ed..8a20e94bec0 100644 --- a/addons/website/static/src/css/editor.css +++ b/addons/website/static/src/css/editor.css @@ -1,4 +1,3 @@ -@charset "utf-8"; .oe_hidden { display: none !important; } @@ -59,6 +58,7 @@ display: none; } +/* ---- SNIPPET EDITOR ---- */ .oe_snippets { position: fixed; left: 0px; @@ -69,6 +69,7 @@ background: #282828; box-shadow: 0px 10px 10px -10px black inset; overflow-y: auto; + z-index: 100; } .oe_snippet { @@ -80,12 +81,12 @@ border-radius: 3px; margin: 10px; margin-right: 0px; - cursor: move; position: relative; box-shadow: 0px 3px 10px rgba(0, 0, 0, 0.2); overflow: hidden; -webkit-user-select: none; user-select: none; + cursor: move; } .oe_snippet .oe_snippet_thumbnail.oe_label { text-align: center; @@ -109,43 +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_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_drop_zone.oe_hover { + 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_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; @@ -158,7 +227,6 @@ border-radius: 10px; border-color: #1a1a1a; margin: auto; - position: absolute; top: 0; left: 0; bottom: 0; diff --git a/addons/website/static/src/css/editor.sass b/addons/website/static/src/css/editor.sass index 7ed368aca47..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 @@ -71,12 +74,12 @@ border-radius: 3px margin: 10px margin-right: 0px - cursor: move position: relative box-shadow: 0px 3px 10px rgba(0,0,0,0.2) overflow: hidden -webkit-user-select: none user-select: none + cursor: move .oe_snippet_thumbnail.oe_label text-align: center @@ -99,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 @@ -112,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 @@ -128,6 +129,65 @@ &.oe_hover:before border-top: dashed 2px rgba(116, 255, 161, 0.72) +.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: 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% overflow: hidden @@ -142,7 +202,6 @@ $mobile_preview_close: #E00101 border-radius: 10px border-color: $mobile_preview_border margin: auto - position: absolute top: 0 left: 0 bottom: 0 diff --git a/addons/website/static/src/css/website.css b/addons/website/static/src/css/website.css index eea25bea19d..4567384975d 100644 --- a/addons/website/static/src/css/website.css +++ b/addons/website/static/src/css/website.css @@ -1,4 +1,3 @@ -@charset "utf-8"; /* THIS CSS FILE IS FOR WEBSITE THEMING CUSTOMIZATION ONLY * * css for editor buttons, openerp widget included in the website and other @@ -159,3 +158,7 @@ header.navbar-fixed-top { min-height: 300px; color: white; } + +.dark { + background: #eff8f8; +} diff --git a/addons/website/static/src/css/website.sass b/addons/website/static/src/css/website.sass index 13037deb2d7..8b885c548d1 100644 --- a/addons/website/static/src/css/website.sass +++ b/addons/website/static/src/css/website.sass @@ -119,4 +119,7 @@ header.navbar-fixed-top min-height: 300px color: white +.dark + background: rgb(239, 248, 248) + diff --git a/addons/website/static/src/js/website.js b/addons/website/static/src/js/website.js index 361cbd6bb8a..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 { @@ -307,6 +307,34 @@ } }); + website.mutations = { + darken: function($el){ + if($el.parent().hasClass('dark')){ + $el.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()' : ''); + $('html').css({'-webkit-filter': filter}); hue += 5; + if(hue % 35 === 0){ + beat = !beat; + } + }, 10); + },5000); + $('').appendTo($el); + }, + }; + /* ----- SNIPPET SELECTOR ---- */ website.Snippets = openerp.Widget.extend({ template: 'website.snippets', @@ -327,20 +355,36 @@ }); }, + path_eval: function(path){ + var obj = window; + path = path.split('.'); + do{ + obj = obj[path.shift()]; + }while(path.length && obj); + return obj; + }, + // setup widget and drag and drop start_snippets: function(){ var self = this; - + 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(){ @@ -353,27 +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(); }, }); + }, - // 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(); @@ -413,7 +463,7 @@ $zones.remove(); }while(count > 0); - // Cleaning up zones placed between floating or inline elements + // Cleaning up zones placed between floating or inline elements. We do not like these kind of zones. var $zones = $('.oe_drop_zone'); for( var i = 0, len = $zones.length; i < len; i++ ){ var zone = $zones.eq(i); @@ -427,36 +477,124 @@ && (float_next === 'left' || float_next === 'right') ){ zone.remove(); continue; - }else if( !( disp_prev === null - || disp_next === null - || disp_prev === 'block' - || disp_next === 'block' - ) ){ + }else if( !( disp_prev === null + || disp_next === null + || disp_prev === 'block' + || disp_next === 'block' )){ zone.remove(); continue; } } }, - deactivate_drop_zones: function(){ + deactivate_zones: function(){ $('.oe_drop_zone').remove(); }, + + activate_overlay_zones: function(selector){ + var $targets = $(selector); + + function is_visible($el){ + return $el.css('display') != 'none' + && $el.css('opacity') != '0' + && $el.css('visibility') != 'hidden'; + } + + // filter out invisible elements + $targets = $targets.filter(function(){ return is_visible($(this)); }); + + // filter out elements with invisible parents + $targets = $targets.filter(function(){ + 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'); + $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(); } }, - snippet_start: function () { - var self = this; - $('.oe_snippet').draggable().click(function(ev) { - self.setup_droppable(); - $(".oe_snippet_drop").show(); - $('.oe_selected').removeClass('oe_selected'); - $(ev.currentTarget).addClass('oe_selected'); - }); - - }, }); function noop() {} diff --git a/addons/website/static/src/xml/website.xml b/addons/website/static/src/xml/website.xml index 9a7f45d396a..39d62ed4f04 100644 --- a/addons/website/static/src/xml/website.xml +++ b/addons/website/static/src/xml/website.xml @@ -2,75 +2,81 @@ - - -