[IMP] website: create a media snippet editor who merge image dialog, font awesome, video youtube...

bzr revid: chm@openerp.com-20140409161538-uogr3vi552begja5
This commit is contained in:
chm@openerp.com
2014-04-09 18:15:38 +02:00
17 changed files with 1383 additions and 386 deletions
+33 -23
View File
@@ -247,37 +247,47 @@ class Website(openerp.addons.web.controllers.main.Home):
return True
@http.route('/website/attach', type='http', auth='user', methods=['POST'], website=True)
def attach(self, func, upload):
def attach(self, func, upload=None, url=None):
Attachments = request.registry['ir.attachment']
url = message = None
try:
image_data = upload.read()
image = Image.open(cStringIO.StringIO(image_data))
w, h = image.size
if w*h > 42e6: # Nokia Lumia 1020 photo resolution
raise ValueError(
u"Image size excessive, uploaded images must be smaller "
u"than 42 million pixel")
Attachments = request.registry['ir.attachment']
website_url = message = None
if not upload:
website_url = url
name = url.split("/").pop()
attachment_id = Attachments.create(request.cr, request.uid, {
'name': upload.filename,
'datas': image_data.encode('base64'),
'datas_fname': upload.filename,
'name':name,
'type': 'url',
'url': url,
'res_model': 'ir.ui.view',
}, request.context)
else:
try:
image_data = upload.read()
image = Image.open(cStringIO.StringIO(image_data))
w, h = image.size
if w*h > 42e6: # Nokia Lumia 1020 photo resolution
raise ValueError(
u"Image size excessive, uploaded images must be smaller "
u"than 42 million pixel")
[attachment] = Attachments.read(
request.cr, request.uid, [attachment_id], ['website_url'],
context=request.context)
url = attachment['website_url']
except Exception, e:
logger.exception("Failed to upload image to attachment")
message = unicode(e)
attachment_id = Attachments.create(request.cr, request.uid, {
'name': upload.filename,
'datas': image_data.encode('base64'),
'datas_fname': upload.filename,
'res_model': 'ir.ui.view',
}, request.context)
[attachment] = Attachments.read(
request.cr, request.uid, [attachment_id], ['website_url'],
context=request.context)
website_url = attachment['website_url']
except Exception, e:
logger.exception("Failed to upload image to attachment")
message = unicode(e)
return """<script type='text/javascript'>
window.parent['%s'](%s, %s);
</script>""" % (func, json.dumps(url), json.dumps(message))
</script>""" % (func, json.dumps(website_url), json.dumps(message))
@http.route(['/website/publish'], type='json', auth="public", website=True)
def publish(self, id, object):
+1 -1
View File
@@ -638,7 +638,7 @@ class ir_attachment(osv.osv):
# in-document URLs are html-escaped, a straight search will not
# find them
url = werkzeug.utils.escape(attachment.website_url)
ids = Views.search(cr, uid, [('arch', 'like', url)], context=context)
ids = Views.search(cr, uid, ["|", ('arch', 'like', '"%s"' % url), ('arch', 'like', "'%s'" % url)], context=context)
if ids:
removal_blocked_by[attachment.id] = Views.read(
+29 -4
View File
@@ -94,6 +94,10 @@
display: none;
}
.cke_editable .css_editable_mode_display {
display: block !important;
}
.oe_structure.oe_empty:empty, [data-oe-type=html]:empty, .oe_structure.oe_empty > .oe_drop_zone.oe_insert:only-child, [data-oe-type=html] > .oe_drop_zone.oe_insert:only-child {
background-image: url("/website/static/src/img/edit_here.png") !important;
}
@@ -180,7 +184,7 @@ ul.oe_menu_editor .disclose {
cursor: text !important;
}
.modal-dialog.select-image {
.modal-dialog.select-media {
width: 80%;
}
@@ -212,7 +216,7 @@ ul.oe_menu_editor .disclose {
.modal .font-icons-icons {
font-size: 2em;
max-height: 6em;
max-height: 9em;
overflow: auto;
}
.modal .font-icons-icons .font-icons-icon {
@@ -271,6 +275,10 @@ ul.oe_menu_editor .disclose {
-webkit-border-bottom-right-radius: 8px;
border-bottom-right-radius: 8px;
}
.existing-attachments .existing-attachment-cell.media_selected > i, .existing-attachments .existing-attachment-cell.media_selected > img {
border-width: 5px;
border-color: #00f8f8;
}
.cke_widget_wrapper {
position: static !important;
@@ -296,17 +304,34 @@ ul.oe_menu_editor .disclose {
background-color: #ffd9dd !important;
}
.hover-edition-button {
.hover-edition {
display: inline-block;
position: absolute;
top: 0;
left: 0;
z-index: 1000;
z-index: 1001;
}
.preview-container {
text-align: center;
line-height: 100px;
height: 100px;
}
.preview-container > * {
max-height: 100px;
line-height: 100px;
margin: 0 auto;
display: inline-block;
}
.cke_editable .fa {
cursor: pointer;
}
.img-responsive {
text-align: center;
}
/* ---- MOBILE PREVIEW ---- {{{ */
.oe_mobile_preview.modal .modal-content {
height: 660px;
+25 -5
View File
@@ -77,6 +77,9 @@
.cke_editable .css_editable_mode_hidden
display: none
.cke_editable .css_editable_mode_display
display: block !important
.oe_structure.oe_empty:empty, [data-oe-type=html]:empty, .oe_structure.oe_empty > .oe_drop_zone.oe_insert:only-child, [data-oe-type=html] > .oe_drop_zone.oe_insert:only-child
background-image: url('/website/static/src/img/edit_here.png') !important
@@ -150,7 +153,7 @@ ul.oe_menu_editor
+user-select(auto)
cursor: text !important
.modal-dialog.select-image
.modal-dialog.select-media
width: 80%
.modal .existing-attachments
@@ -179,7 +182,7 @@ ul.oe_menu_editor
.modal
.font-icons-icons
font-size: 2em
max-height: 6em
max-height: 9em
overflow: auto
.font-icons-icon
@@ -232,6 +235,10 @@ $attachment-border-color: #848490
border-top: none
border-left: none
+border-bottom-right-radius(8px)
&.media_selected
> i, > img
border-width: 5px
border-color: rgb(0, 248, 248)
// wrapper positioned relatively for drag&drop widget which is disabled below.
// Breaks completely horribly crazy products listing page, so take it out.
@@ -259,17 +266,30 @@ $attachment-border-color: #848490
outline: 1px solid red !important
background-color: #ffd9dd !important
.hover-edition-button
.hover-edition
display: inline-block
position: absolute
top: 0
left: 0
// This z-index is due to .navbar of bootstrap
z-index: 1000
// This z-index is due to .navbar of bootstrap & jQuery-transfo
z-index: 1001
.preview-container
text-align: center
line-height: 100px
height: 100px
> *
max-height: 100px
line-height: 100px
margin: 0 auto
display: inline-block
// fontawesome
.cke_editable .fa
cursor: pointer
.img-responsive
text-align: center
// }}}
/* ---- MOBILE PREVIEW ---- {{{ */
+10 -5
View File
@@ -201,6 +201,7 @@
height: 0;
position: absolute;
background: transparent;
z-index: 1001;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
-ms-border-radius: 3px;
@@ -325,11 +326,13 @@
top: auto;
left: 50%;
bottom: -6px;
margin-left: -50px;
}
.oe_overlay .oe_handle.size .oe_handle_button {
position: relative;
z-index: 3;
text-align: center;
margin-left: -32px;
margin-left: -52px;
margin-top: -10px;
left: 0px;
}
@@ -341,15 +344,17 @@
box-shadow: 0 0 5px 3px rgba(255, 255, 255, 0.7);
}
.oe_overlay .oe_handle.size .size {
position: absolute;
width: 64px;
cursor: row-resize;
top: 9px;
margin-left: 52px;
padding: 0 5px;
}
.oe_overlay .oe_handle.size .auto_size {
width: 20px;
padding: 0 5px;
top: 1px;
margin-left: 36px;
position: absolute;
width: 100px;
top: 9px;
cursor: pointer;
}
.oe_overlay .oe_handle.readonly {
+10 -5
View File
@@ -151,6 +151,7 @@
height: 0
position: absolute
background: transparent
z-index: 1001
//@include background-image( repeating-linear-gradient(45deg, rgba(255,255,255,.02) ,rgba(255,255,255,.02) 35px, rgba(0,0,0,.02) 35px, rgba(0,0,0,.02) 75px))
+border-radius(3px)
@include transition(opacity 100ms linear)
@@ -238,10 +239,12 @@
top: auto
left: 50%
bottom: -6px
margin-left: -50px
.oe_handle_button
position: relative
z-index: 3
text-align: center
margin-left: -32px
margin-left: -52px
margin-top: -10px
left: 0px
&:hover
@@ -249,14 +252,16 @@
color: #fff
+box-shadow(0 0 5px 3px rgba(255,255,255,.7))
.size
position: absolute
width: 64px
cursor: row-resize
top: 9px
.auto_size
width: 20px
margin-left: 52px
padding: 0 5px
top: 1px
margin-left: 36px
.auto_size
position: absolute
width: 100px
top: 9px
cursor: pointer
&.readonly
cursor: auto !important
+46 -4
View File
@@ -373,11 +373,23 @@ ul.nav-stacked > li > a {
position: absolute;
margin-top: -8px;
}
.carousel .carousel-control.left span {
left: 10px;
.carousel .carousel-control.left {
left: -10px;
}
.carousel .carousel-control.right span {
right: 10px;
.carousel .carousel-control.left * {
position: absolute;
top: 50%;
z-index: 5;
right: 50%;
}
.carousel .carousel-control.right {
right: -10px;
}
.carousel .carousel-control.right * {
position: absolute;
top: 50%;
z-index: 5;
left: 50%;
}
.quotecarousel {
@@ -528,3 +540,33 @@ span[data-oe-type="monetary"] {
width: 400px;
margin: 40px auto;
}
div.media_iframe_video {
height: 0;
margin: 0 auto;
text-align: center;
position: relative;
overflow: hidden;
padding-bottom: 66.5%;
}
div.media_iframe_video iframe {
width: 100%;
height: 100%;
}
div.media_iframe_video div {
position: absolute;
width: 100%;
height: 100%;
display: none;
}
/* Mobile view */
@media (max-width: 768px) {
img:not(.cke_iframe), .media_iframe_video, span.fa, i.fa {
-webkit-transform: none !important;
-moz-transform: none !important;
-ms-transform: none !important;
-o-transform: none !important;
transform: none !important;
}
}
+39 -4
View File
@@ -306,10 +306,20 @@ ul.nav-stacked > li > a
top: 50%
position: absolute
margin-top: -8px
&.left span
left: 10px
&.right span
right: 10px
&.left
left: -10px
*
position: absolute
top: 50%
z-index: 5
right: 50%
&.right
right: -10px
*
position: absolute
top: 50%
z-index: 5
left: 50%
.quotecarousel
padding-bottom: 16px
@@ -435,3 +445,28 @@ span[data-oe-type="monetary"]
overflow:hidden
text-overflow:ellipsis
div.media_iframe_video
height: 0
margin: 0 auto
text-align: center
position: relative
overflow: hidden
padding-bottom: 66.5%
iframe
width: 100%
height: 100%
div
position: absolute
width: 100%
height: 100%
display: none
/* Mobile view */
@media (max-width: 768px)
img:not(.cke_iframe), .media_iframe_video, span.fa, i.fa
-webkit-transform: none !important
-moz-transform: none !important
-ms-transform: none !important
-o-transform: none !important
transform: none !important
@@ -0,0 +1,433 @@
/*
Copyright (c) 2014 Christophe Matthieu,
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/
(function($){
'use strict';
var rad = Math.PI/180;
// public methods
var methods = {
init : function(settings) {
return this.each(function() {
var $this = $(this), transfo = $this.data('transfo');
if (!transfo) {
_init($this, settings);
} else {
_overwriteOptions($this, transfo, settings);
_targetCss($this, transfo);
}
});
},
destroy : function() {
return this.each(function() {
var $this = $(this);
if ($this.data('transfo')) {
_destroy($this);
}
});
},
reset : function() {
return this.each(function() {
var $this = $(this);
if ($this.data('transfo')) {
_reset($this);
}
});
},
toggle : function() {
return this.each(function() {
var $this = $(this);
var transfo = $this.data('transfo');
if (transfo) {
transfo.settings.hide = !transfo.settings.hide;
_showHide($this, transfo);
}
});
},
hide : function() {
return this.each(function() {
var $this = $(this);
var transfo = $this.data('transfo');
if (transfo) {
transfo.settings.hide = true;
_showHide($this, transfo);
}
});
},
show : function() {
return this.each(function() {
var $this = $(this);
var transfo = $this.data('transfo');
if (transfo) {
transfo.settings.hide = false;
_showHide($this, transfo);
}
});
},
settings : function() {
if(this.length > 1) {
this.map(function () {
var $this = $(this);
return $this.data('transfo') && $this.data('transfo').settings;
});
}
return this.data('transfo') && $this.data('transfo').settings;
},
center : function() {
if(this.length > 1) {
this.map(function () {
var $this = $(this);
return $this.data('transfo') && $this.data('transfo').$center.offset();
});
}
return this.data('transfo') && this.data('transfo').$center.offset();
}
};
$.fn.transfo = function( method ) {
if ( methods[method] ) {
return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ));
} else if ( typeof method === 'object' || ! method ) {
return methods.init.apply( this, arguments );
} else {
$.error( 'Method ' + method + ' does not exist on jQuery.transfo' );
}
return false;
};
function _init ($this, settings) {
var transfo = {};
$this.data('transfo', transfo);
transfo.settings = settings;
// generate all the controls markup
var css = "box-sizing: border-box; position: absolute; background-color: #fff; border: 1px solid #ccc; width: 8px; height: 8px; margin-left: -4px; margin-top: -4px;";
transfo.$markup = $(''
+ '<div class="transfo-controls">'
+ '<div style="cursor: crosshair; position: absolute; margin: -30px; top: 0; right: 0; padding: 1px 0 0 1px;" class="transfo-rotator">'
+ '<span class="fa-stack fa-lg">'
+ '<i class="fa fa-circle fa-stack-2x"></i>'
+ '<i class="fa fa-repeat fa-stack-1x fa-inverse"></i>'
+ '</span>'
+ '</div>'
+ '<div style="' + css + 'top: 0%; left: 0%; cursor: nw-resize;" class="transfo-scaler-tl"></div>'
+ '<div style="' + css + 'top: 0%; left: 100%; cursor: ne-resize;" class="transfo-scaler-tr"></div>'
+ '<div style="' + css + 'top: 100%; left: 100%; cursor: se-resize;" class="transfo-scaler-br"></div>'
+ '<div style="' + css + 'top: 100%; left: 0%; cursor: sw-resize;" class="transfo-scaler-bl"></div>'
+ '<div style="' + css + 'top: 0%; left: 50%; cursor: n-resize;" class="transfo-scaler-tc"></div>'
+ '<div style="' + css + 'top: 100%; left: 50%; cursor: s-resize;" class="transfo-scaler-bc"></div>'
+ '<div style="' + css + 'top: 50%; left: 0%; cursor: w-resize;" class="transfo-scaler-ml"></div>'
+ '<div style="' + css + 'top: 50%; left: 100%; cursor: e-resize;" class="transfo-scaler-mr"></div>'
+ '<div style="' + css + 'border: 0; width: 0px; height: 0px; top: 50%; left: 50%;" class="transfo-scaler-mc"></div>'
+ '</div>');
transfo.$center = transfo.$markup.find(".transfo-scaler-mc");
// init setting and get css to set wrap
_setOptions($this, transfo);
_overwriteOptions ($this, transfo, settings);
// append controls to container
$("body").append(transfo.$markup);
// set transfo container and markup
setTimeout(function () {
_targetCss($this, transfo);
},0);
_bind($this, transfo);
_targetCss($this, transfo);
}
function _overwriteOptions ($this, transfo, settings) {
transfo.settings = $.extend(transfo.settings, settings || {});
}
function _setOptions ($this, transfo) {
var style = $this.attr("style") || "";
var transform = style.match(/transform\s*:([^;]+)/) ? style.match(/transform\s*:([^;]+)/)[1] : "";
transfo.settings = {};
transfo.settings.angle= transform.indexOf('rotate') != -1 ? parseFloat(transform.match(/rotate\(([^)]+)deg\)/)[1]) : 0;
transfo.settings.scalex= transform.indexOf('scaleX') != -1 ? parseFloat(transform.match(/scaleX\(([^)]+)\)/)[1]) : 1;
transfo.settings.scaley= transform.indexOf('scaleY') != -1 ? parseFloat(transform.match(/scaleY\(([^)]+)\)/)[1]) : 1;
transfo.settings.style = style.replace(/[^;]*transform[^;]+/g, '').replace(/;+/g, ';');
$this.attr("style", transfo.settings.style);
transfo.settings.height = $this.innerHeight();
transfo.settings.width = $this.innerWidth();
var translatex = transform.match(/translateX\(([0-9.-]+)(%|px)\)/);
var translatey = transform.match(/translateY\(([0-9.-]+)(%|px)\)/);
transfo.settings.translate = "%";
if (translatex && translatex[2] === "%") {
transfo.settings.translatexp = parseFloat(translatex[1]);
transfo.settings.translatex = transfo.settings.translatexp / 100 * transfo.settings.width;
} else {
transfo.settings.translatex = translatex ? parseFloat(translatex[1]) : 0;
}
if (translatey && translatey[2] === "%") {
transfo.settings.translateyp = parseFloat(translatey[1]);
transfo.settings.translatey = transfo.settings.translateyp / 100 * transfo.settings.height;
} else {
transfo.settings.translatey = translatey ? parseFloat(translatey[1]) : 0;
}
transfo.settings.css = window.getComputedStyle($this[0], null);
transfo.settings.pos = $this.offset();
transfo.settings.rotationStep = 5;
transfo.settings.hide = false;
transfo.settings.callback = function () {};
}
function _bind ($this, transfo) {
function mousedown (event) {
_mouseDown($this, this, transfo, event);
$(document).on("mousemove", mousemove).on("mouseup", mouseup);
}
function mousemove (event) {
_mouseMove($this, this, transfo, event);
}
function mouseup (event) {
_mouseUp($this, this, transfo, event);
$(document).off("mousemove", mousemove).off("mouseup", mouseup);
}
transfo.$markup.off().on("mousedown", mousedown);
transfo.$markup.find(">:not(.transfo-scaler-mc)").off().on("mousedown", mousedown);
}
function _mouseDown($this, div, transfo, event) {
event.preventDefault();
if (transfo.active || event.which !== 1) return;
var type = "position", $e = $(div);
if ($e.hasClass("transfo-rotator")) type = "rotator";
else if ($e.hasClass("transfo-scaler-tl")) type = "tl";
else if ($e.hasClass("transfo-scaler-tr")) type = "tr";
else if ($e.hasClass("transfo-scaler-br")) type = "br";
else if ($e.hasClass("transfo-scaler-bl")) type = "bl";
else if ($e.hasClass("transfo-scaler-tc")) type = "tc";
else if ($e.hasClass("transfo-scaler-bc")) type = "bc";
else if ($e.hasClass("transfo-scaler-ml")) type = "ml";
else if ($e.hasClass("transfo-scaler-mr")) type = "mr";
transfo.active = {
"type": type,
"scalex": transfo.settings.scalex,
"scaley": transfo.settings.scaley,
"pageX": event.pageX,
"pageY": event.pageY,
"center": transfo.$center.offset(),
};
}
function _mouseUp($this, div, transfo, event) {
transfo.active = null;
}
function _mouseMove($this, div, transfo, event) {
event.preventDefault();
if (!transfo.active) return;
var settings = transfo.settings;
var center = transfo.active.center;
var cdx = center.left - event.pageX;
var cdy = center.top - event.pageY;
if (transfo.active.type == "rotator") {
var ang, dang = Math.atan((settings.width * settings.scalex) / (settings.height * settings.scaley)) / rad;
if (cdy) ang = Math.atan(- cdx / cdy) / rad;
else ang = 0;
if (event.pageY >= center.top && event.pageX >= center.left) ang += 180;
else if (event.pageY >= center.top && event.pageX < center.left) ang += 180;
else if (event.pageY < center.top && event.pageX < center.left) ang += 360;
ang -= dang;
if (settings.scaley < 0 && settings.scalex < 0) ang += 180;
if (!event.ctrlKey) {
settings.angle = Math.round(ang / transfo.settings.rotationStep) * transfo.settings.rotationStep;
} else {
settings.angle = ang;
}
// reset position : don't move center
_targetCss($this, transfo);
var new_center = transfo.$center.offset();
var x = center.left - new_center.left;
var y = center.top - new_center.top;
var angle = ang * rad;
settings.translatex += x*Math.cos(angle) - y*Math.sin(-angle);
settings.translatey += - x*Math.sin(angle) + y*Math.cos(-angle);
}
else if (transfo.active.type == "position") {
var angle = settings.angle * rad;
var x = event.pageX - transfo.active.pageX;
var y = event.pageY - transfo.active.pageY;
transfo.active.pageX = event.pageX;
transfo.active.pageY = event.pageY;
var dx = x*Math.cos(angle) - y*Math.sin(-angle);
var dy = - x*Math.sin(angle) + y*Math.cos(-angle);
settings.translatex += dx;
settings.translatey += dy;
}
else if (transfo.active.type.length === 2) {
var angle = settings.angle * rad;
var dx = cdx*Math.cos(angle) - cdy*Math.sin(-angle);
var dy = - cdx*Math.sin(angle) + cdy*Math.cos(-angle);
if (transfo.active.type.indexOf("t") != -1) {
settings.scaley = dy / (settings.height/2);
}
if (transfo.active.type.indexOf("b") != -1) {
settings.scaley = - dy / (settings.height/2);
}
if (transfo.active.type.indexOf("l") != -1) {
settings.scalex = dx / (settings.width/2);
}
if (transfo.active.type.indexOf("r") != -1) {
settings.scalex = - dx / (settings.width/2);
}
if (settings.scaley > 0 && settings.scaley < 0.05) settings.scaley = 0.05;
if (settings.scalex > 0 && settings.scalex < 0.05) settings.scalex = 0.05;
if (settings.scaley < 0 && settings.scaley > -0.05) settings.scaley = -0.05;
if (settings.scalex < 0 && settings.scalex > -0.05) settings.scalex = -0.05;
if (event.shiftKey &&
(transfo.active.type === "tl" || transfo.active.type === "bl" ||
transfo.active.type === "tr" || transfo.active.type === "br")) {
settings.scaley = settings.scalex;
}
}
settings.angle = Math.round(settings.angle);
settings.translatex = Math.round(settings.translatex);
settings.translatey = Math.round(settings.translatey);
settings.scalex = Math.round(settings.scalex*100)/100;
settings.scaley = Math.round(settings.scaley*100)/100;
_targetCss($this, transfo);
return false;
}
function _setCss($this, css, settings) {
var transform = "";
var trans = false;
if (settings.angle !== 0) {
trans = true;
transform += " rotate("+settings.angle+"deg) ";
}
if (settings.translatex) {
trans = true;
transform += " translateX("+(settings.translate === "%" ? settings.translatexp+"%" : settings.translatex+"px")+") ";
}
if (settings.translatey) {
trans = true;
transform += " translateY("+(settings.translate === "%" ? settings.translateyp+"%" : settings.translatey+"px")+") ";
}
if (settings.scalex != 1) {
trans = true;
transform += " scaleX("+settings.scalex+") ";
}
if (settings.scaley != 1){
trans = true;
transform += " scaleY("+settings.scaley+") ";
}
if (trans) {
css += ";"
/* Safari */
css += "-webkit-transform:" + transform + ";"
/* Firefox */
+ "-moz-transform:" + transform + ";"
/* IE */
+ "-ms-transform:" + transform + ";"
/* Opera */
+ "-o-transform:" + transform + ";"
/* Other */
+ "transform:" + transform + ";";
}
css = css.replace(/(\s*;)+/g, ';').replace(/^\s*;|;\s*$/g, '');
$this.attr("style", css);
}
function _targetCss ($this, transfo) {
var settings = transfo.settings;
var width = parseFloat(settings.css.width);
var height = parseFloat(settings.css.height);
settings.translatexp = Math.round(settings.translatex/width*1000)/10;
settings.translateyp = Math.round(settings.translatey/height*1000)/10;
_setCss($this, settings.style, settings);
_setCss(transfo.$markup,
"position: absolute;" +
"top:" + settings.pos.top + "px;" +
"left:" + settings.pos.left + "px;" +
"width:" + width + "px;" +
"height:" + height + "px;" +
"cursor: move;",
settings);
transfo.$markup.find(">").css("transform", "scaleX("+(1/settings.scalex)+") scaleY("+(1/settings.scaley)+")");
_showHide($this, transfo);
transfo.settings.callback.call($this[0], $this);
}
function _showHide ($this, transfo) {
transfo.$markup.css("z-index", transfo.settings.hide ? -1 : 1000);
if (transfo.settings.hide) {
transfo.$markup.find(">").hide();
transfo.$markup.find(".transfo-scaler-mc").show();
} else {
transfo.$markup.find(">").show();
}
}
function _destroy ($this) {
$this.data('transfo').$markup.remove();
$this.removeData('transfo');
}
function _reset ($this) {
var transfo = $this.data('transfo');
_destroy($this);
$this.transfo(transfo.settings);
}
})(jQuery);
File diff suppressed because one or more lines are too long
@@ -148,4 +148,11 @@
});
},
});
website.snippet.animationRegistry.media_video = website.snippet.Animation.extend({
selector: ".media_iframe_video",
start: function () {
this.$target.html('<div class="css_editable_mode_display">&nbsp;</div><iframe src="'+this.$target.data("src")+'" frameborder="0" allowfullscreen="allowfullscreen"></iframe>');
},
});
})();
@@ -154,6 +154,7 @@
this.on('rte:ready', this, function () {
self.snippets.$button.removeClass("hidden");
website.snippet.stop_animation();
website.snippet.start_animation(true, $(".media_iframe_video"));
});
return this._super.apply(this, arguments);
@@ -265,7 +266,8 @@
'$el': $style,
'selector-siblings': $style.data('selector-siblings'),
'selector-children': $style.data('selector-children'),
'selector-vertical-children': $style.data('selector-vertical-children')
'selector-vertical-children': $style.data('selector-vertical-children'),
'data': $style.data()
};
selector.push($style.data('selector'));
});
@@ -332,6 +334,7 @@
if (!$target.is(website.snippet.globalSelector)) {
$target = $target.parents(website.snippet.globalSelector).first();
}
if (!self.dom_filter($target).length) {
$target = false;
}
@@ -732,12 +735,15 @@
this.$target.data("snippet-option-ids", styles);
this.$overlay = this.$target.data('overlay');
this['snippet-option-id'] = snippet_id;
this.$el = website.snippet.templateOptions[snippet_id].$el.find(">li").clone();
var $option = website.snippet.templateOptions[snippet_id].$el;
this.$el = $option.find(">li").clone();
this.data = $option.data();
this.required = this.$el.data("required");
this.set_active();
this.$el.find('li[data-value] a').on('mouseover mouseout click', _.bind(this._mouse, this));
this.$el.find('li[data-value] a').on('mouseenter mouseleave click', _.bind(this._mouse, this));
this.$el.not(':not([data-value])').find("a").on('mouseenter mouseleave click', _.bind(this._mouse, this));
this.$target.on('snippet-style-reset', _.bind(this.set_active, this));
this.start();
@@ -745,7 +751,7 @@
_mouse: function (event) {
var self = this;
if (event.type === 'mouseout') {
if (event.type === 'mouseleave') {
if (!this.over) return;
this.over = false;
} else if (event.type === 'click') {
@@ -755,7 +761,7 @@
}
var $prev, $next;
if (event.type === 'mouseout') {
if (event.type === 'mouseleave') {
$prev = $(event.currentTarget).parent();
$next = this.$el.find("li[data-value].active");
} else {
@@ -837,7 +843,7 @@
var self = this;
// add or remove html class
if (np.$prev && this.required) {
if (np.$prev) {
this.$target.removeClass(np.$prev.data('value') || "");
}
if (np.$next) {
@@ -927,7 +933,7 @@
drop_and_build_snippet: function() {
this.id = this.unique_id();
this.$target.attr("id", this.id);
this.$target.find("[data-slide]").attr("href", "#" + this.id);
this.$target.find("[data-slide]").attr("data-target", "#" + this.id);
this.$target.find("[data-slide-to]").attr("data-target", "#" + this.id);
this.rebind_event();
@@ -1171,6 +1177,7 @@
dy = dy - dy%resize;
if (dy <= 0) dy = resize;
self.$target.css("height", dy+"px");
self.$target.css("overflow", "hidden");
self.on_resize(compass, null, dy);
self.BuildingBlock.cover_target(self.$overlay, self.$target);
return;
@@ -1211,6 +1218,7 @@
});
this.$overlay.find(".oe_handle.size .auto_size").on('click', function (event){
self.$target.css("height", "");
self.$target.css("overflow", "");
self.BuildingBlock.cover_target(self.$overlay, self.$target);
return false;
});
@@ -1425,6 +1433,88 @@
}
});
website.snippet.options.transform = website.snippet.Option.extend({
start: function () {
var self = this;
this._super();
this.$el.find(".clear-style").click(function (event) {
self.$target.removeClass("fa-spin").attr("style", "");
self.resetTransfo();
});
this.$el.find(".style").click(function (event) {
var settings = self.$target.data("transfo").settings;
self.$target.transfo({ hide: (settings.hide = !settings.hide) });
});
this.$overlay.find('.oe_snippet_clone, .oe_handles').addClass('hidden');
this.$overlay.find('[data-toggle="dropdown"]')
.on("mousedown", function () {
self.$target.transfo("hide");
});
},
resetTransfo: function () {
var self = this;
this.$target.transfo("destroy");
this.$target.transfo({
hide: true,
callback: function () {
var pos = $(this).data("transfo").$center.offset();
self.$overlay.css({
'top': pos.top,
'left': pos.left,
'position': 'absolute',
});
self.$overlay.find(".oe_overlay_options").attr("style", "width:0; left:0!important; top:0;");
self.$overlay.find(".oe_overlay_options > .btn-group").attr("style", "width:160px; left:-80px;");
}});
this.$target.data('transfo').$markup
.on("mouseover", function () {
self.$target.trigger("mouseover");
})
.mouseover();
},
onFocus : function () {
this.resetTransfo();
},
onBlur : function () {
this.$target.transfo("hide");
},
});
website.snippet.options.media = website.snippet.Option.extend({
start: function () {
var self = this;
this._super();
website.snippet.start_animation(true, this.$target);
$(document.body).on("media-saved", self, function (event, prev , item) {
self.editor.onBlur();
self.BuildingBlock.make_active(false);
self.BuildingBlock.make_active($(item));
});
this.$el.find(".edition").click(function (event) {
event.preventDefault();
event.stopPropagation();
self.element = new CKEDITOR.dom.element(self.$target[0]);
new website.editor.MediaDialog(self, self.element).appendTo(document.body);
});
},
onFocus : function () {
var self = this;
if (this.$target.parent().data("oe-field") === "image") {
this.$overlay.addClass("hidden");
self.element = new CKEDITOR.dom.element(self.$target[0]);
new website.editor.MediaDialog(self, self.element).appendTo(document.body);
self.BuildingBlock.make_active(false);
}
},
});
website.snippet.Editor = openerp.Class.extend({
init: function (BuildingBlock, dom) {
@@ -1564,6 +1654,10 @@
if (this.selector_vertical_children === "")
this.selector_vertical_children = false;
if (!this.selector_siblings && !this.selector_children && !this.selector_vertical_children) {
this.$overlay.find(".oe_snippet_move").addClass('hidden');
}
if ($ul.find("li").length) {
$styles.removeClass("hidden");
+155 -84
View File
@@ -88,49 +88,85 @@
</form>
</t>
</t>
<t t-name="website.editor.dialog.image">
<t t-call="website.editor.dialog">
<t t-set="title">Image:</t>
<div class="row">
<form method="POST" action="/website/attach"
enctype="multipart/form-data"
target="fileframe"
class="col-sm-8">
<div class="text-center">
<input type="file" name="upload" accept="image/*" style="position: absolute; opacity: 0; width: 1px; height: 1px;"/>
<button type="button" class="btn btn-primary btn-lg filepicker">
Upload an image from your computer
</button>
<button type="button" class="btn btn-lg hidden wait" disabled="disabled"/>
<p class="text-muted mt16">— or —</p>
<t t-name="website.editor.dialog.media">
<div class="modal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog select-media">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h3 class="modal-title">Select a Media</h3>
</div>
<div class="well">
<a href="#existing" class="pull-right">Browse existing images</a>
<h3 class="list-group-item-heading">Image URL</h3>
<input type="text" class="form-control url"
placeholder="http://openerp.com"/>
<div class="modal-body">
<ul class="nav nav-tabs">
<li class="active"><a href="#editor-media-image" data-toggle="tab">Image</a></li>
<li><a href="#editor-media-icon" data-toggle="tab">Pictogram</a></li>
<li><a href="#editor-media-video" data-toggle="tab">Video</a></li>
<li class="search" style="float: right;">
<ul class="pager mb0 mt0">
<li class="previous disabled"><a href="#">← Previous</a></li>
<li class="next disabled"><a href="#">Next →</a></li>
</ul>
</li>
<li class="search" style="float: right;">
<form action="#">
<div class="form-group font-icons fa fa-search mb0">
<input type="search" class="form-control" id="icon-search"/>
</div>
</form>
</li>
</ul>
<!-- Tab panes -->
<div class="tab-content">
<div class="tab-pane fade in active" id="editor-media-image">
</div>
<div class="tab-pane fade" id="editor-media-icon">
</div>
<div class="tab-pane fade" id="editor-media-video">
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary save">Save</button>
<button type="button" class="btn hidden wait" disabled="disabled"/>
or
<a href="#" data-dismiss="modal" aria-hidden="true">Discard</a>
</div>
<input type="hidden" name="func"/>
<div class="help-block"/>
</form>
<div class="col-sm-4 image-preview-container">
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAC0lEQVQIHWP4zwAAAgEBAMVfG14AAAAASUVORK5CYII%3D"
class="pull-right img-rounded image-preview"
width="100%"/>
<img src="/web/static/src/img/throbber-large.gif"
class="pull-right img-rounded wait hidden"
width="100%"/>
<select class="form-control image-style">
<option value="">No styling</option>
<option value="img-rounded">Rounded corners</option>
<option value="img-thumbnail">Box</option>
<option value="img-circle">Circle</option>
<option value="shadow">Shadow</option>
</select>
</div>
</div>
<iframe src="about:blank" name="fileframe" class="hidden"/>
</t>
</div>
</t>
<t t-name="website.editor.dialog.image">
<div>
<form method="POST"
action="/website/attach"
enctype="multipart/form-data"
target="fileframe"
class="form-inline">
<div class="well">
<div class="form-group pull-left">
<input type="file" name="upload" accept="image/*" style="position: absolute; opacity: 0; width: 1px; height: 1px;"/>
<button type="button" class="btn btn-primary filepicker">Upload an image from your computer</button>
<button type="button" class="btn hidden wait" disabled="disabled">Uploading...</button>
</div>
<div>
<span class="text-muted"> — or — </span>
<label for="iamgeurl">Add an image URL</label>
<div class="form-group btn-group">
<input type="text" name="url" class="form-control url pull-left" style="width: 320px;" id="iamgeurl" placeholder="http://openerp.com/logo.png"/>
<button class="btn btn-default" type="submit">Add</button>
</div>
</div>
</div>
<input type="hidden" name="func"/>
<div class="help-block"/>
<div class="existing-attachments"/>
</form>
</div>
<iframe src="about:blank" name="fileframe" class="hidden"/>
</t>
<t t-name="website.editor.dialog.image.existing">
<div class="modal" tabindex="-1" role="dialog" aria-hidden="true">
@@ -153,15 +189,11 @@
</t>
<t t-name="website.editor.dialog.image.existing.content">
<div class="existing-attachments">
<ul class="pager">
<li class="previous disabled"><a href="#">← Previous</a></li>
<li class="next disabled"><a href="#">Next →</a></li>
</ul>
<div class="row mt16" t-foreach="rows" t-as="row">
<div class="col-sm-2 existing-attachment-cell"
t-foreach="row" t-as="attachment">
<i class="fa fa-times existing-attachment-remove" t-att-data-id="attachment.id"/>
<img t-att-src="attachment.website_url" t-att-alt="attachment.name" class="img img-responsive"/>
<img t-att-src="attachment.website_url" t-att-alt="attachment.name" t-att-title="attachment.name" class="img img-responsive"/>
</div>
</div>
</div>
@@ -174,7 +206,7 @@
<li>
<a t-attf-href="/web#model=ir.ui.view&amp;id=#{view.id}">
<t t-esc="view.name"/>
</a> (id <t t-esc="view.id"/>)
</a>
</li>
</ul>
</div>
@@ -217,49 +249,42 @@
</div>
</t>
<t t-name="website.editor.hoverbutton">
<button type="button" contenteditable="false"
t-attf-class="btn btn-primary hover-edition-button #{classes or ''}">
<t t-esc="label"/>
</button>
<t t-name="website.editor.hoverbutton.link">
<button contentEditable="false" type="button" class="btn btn-primary hover-edition-button btn-xs">Change</button>
</t>
<t t-name="website.editor.hoverbutton.media">
<div contentEditable="false" class="hover-edition dropdown">
<a class="btn btn-primary btn-sm" data-toggle="dropdown" href="#">Customize</a>
<ul class="dropdown-menu" role="menu" aria-labelledby="dLabel">
<li><a href="#" class="hover-edition-button">Change Media</a></li>
<li><a href="#" class="hover-style-button">Style</a></li>
<li class="dropdown-submenu">
<a href="#" tabindex="-1">Rotation</a>
<ul class="dropdown-menu">
<li data-value="fa-spin"><a>Spin</a></li>
<li data-value="fa-flip-horizontal"><a>Horizontal flip</a></li>
<li data-value="fa-flip-vertical"><a>Vertical flip</a></li>
</ul>
</li>
<li><a href="#" data-value="fa-border">border</a></li>
</ul>
</div>
</t>
<t t-name="website.editor.dialog.font-icons">
<t t-call="website.editor.dialog">
<t t-set="title">Icon:</t>
<form>
<div class="form-group" id="fa-preview">
<form action="#">
<input type="hidden" id="fa-icon"/>
<input type="hidden" id="fa-size"/>
<div class="font-icons-icons">
<t t-call="website.editor.dialog.font-icons.icons">
<t t-set="icons" t-value="widget.icons"/>
</t>
</div>
<div class="form-group mt32" id="fa-preview">
</div>
<div class="form-group font-icons fa fa-search">
<input type="hidden" id="fa-icon" class="form-control"/>
<input type="hidden" id="fa-size" class="form-control"/>
<input type="search" class="form-control" id="icon-search"/>
<div class="font-icons-icons">
<t t-call="website.editor.dialog.font-icons.icons">
<t t-set="icons" t-value="widget.icons"/>
</t>
</div>
</div>
<div class="form-group">
<label for="fa-rotation">Rotation</label>
<select id="fa-rotation" class="form-control">
<option value="">None</option>
<option value="fa-spin">Spin</option>
<option value="fa-rotate-90">Rotate 90º</option>
<option value="fa-rotate-180">Rotate 180º</option>
<option value="fa-rotate-270">Rotate 270º</option>
<option value="fa-flip-horizontal">Horizontal flip</option>
<option value="fa-flip-vertical">Vertical flip</option>
</select>
</div>
<div class="form-group">
<label>
<input type="checkbox" id="fa-border"/> border
</label>
</div>
</form>
</t>
</div>
</form>
</t>
<t t-name="website.editor.dialog.font-icons.icons">
<span t-foreach="icons" t-as="icon"
@@ -269,4 +294,50 @@
</span>
</t>
<t t-name="website.editor.dialog.video">
<form action="#" class="form-inline">
<div class="well">
<div class="form-group btn-group">
<span class="text-muted pull-right" style="margin-left:10px; line-height: 2em;">(Youtube, Vimeo, Dailymotion)</span>
<label for="urlvideo" style="width: 220px; line-height: 2em;" class="pull-left">Set a video URL</label>
<input type="text"
name="url"
class="form-control url pull-left"
style="width: 400px;"
id="urlvideo"
placeholder="//www.youtube.com/embed/yws1tbgNV7k"/>
<button class="btn btn-default">Preview</button>
</div>
<div class="form-group btn-group">
<label for="urlvideo" style="width: 220px; line-height: 2em;" class="pull-left"><span class="text-muted">— or —</span> Embed Video (HTML)</label>
<input type="text"
name="embed"
class="form-control url pull-left"
style="width: 400px;"
id="embedvideo"
placeholder='&lt;iframe src="//www.youtube.com/embed/yws1tbgNV7k"&gt;&lt;/iframe&gt;'/>
<button class="btn btn-default">Preview</button>
</div>
</div>
<div id="video-preview" style="width: 450px; margin: 0 auto;">
<div class="media_iframe_video">
<iframe
src=""
frameborder="0"
allowfullscreen="allowfullscreen"></iframe>
</div>
</div>
<input type="hidden" id="video_id" value=""/>
<input type="hidden" id="video_type" value=""/>
<div class="text-center mt32">
<div class="checkbox">
<label><input type="checkbox" id="autoplay"/> Autoplay</label>
</div>
</div>
</form>
</t>
</templates>
@@ -39,8 +39,8 @@
<div class='oe_handle e readonly'><div></div></div>
<div class='oe_handle w readonly'><div></div></div>
<div class='oe_handle size readonly'>
<div class="oe_handle_button auto_size">Auto Resize</div>
<div class="oe_handle_button size">Resize</div>
<div class="oe_handle_button auto_size">x</div>
</div>
<div class='oe_handle s readonly'><div></div></div>
</div>
+23 -2
View File
@@ -39,8 +39,8 @@
</div>
</div>
</div>
<a class="carousel-control left hidden" href="#myCarousel" data-slide="prev" style="width: 10%"><span class="glyphicon glyphicon-chevron-left"><span class="hidden">.</span></span></a>
<a class="carousel-control right hidden" href="#myCarousel" data-slide="next" style="width: 10%"><span class="glyphicon glyphicon-chevron-right"><span class="hidden">.</span></span></a>
<div class="carousel-control left hidden" data-target="#myCarousel" data-slide="prev" style="width: 10%"><i class="fa fa-chevron-left"></i></div>
<div class="carousel-control right hidden" data-target="#myCarousel" data-slide="next" style="width: 10%"><i class="fa fa-chevron-right"></i></div>
</div>
</div>
@@ -962,6 +962,27 @@
</li>
</div>
<div data-snippet-option-id='media'
data-selector="img:not(.cke_iframe), .media_iframe_video, span.fa, i.fa, .glyphicon">
<li><a href="#" class="edition">Change...</a></li>
</div>
<div data-snippet-option-id='transform'
data-selector="img:not(.cke_iframe), .media_iframe_video, span.fa, i.fa">
<li class="dropdown-submenu">
<a tabindex="-1" href="#">Style</a>
<ul class="dropdown-menu" name="parallax-scroll">
<li data-value="img-rounded"><a>Rounded corners</a></li>
<li data-value="img-thumbnail"><a>Box</a></li>
<li data-value="img-circle"><a>Circle</a></li>
<li data-value="shadow"><a>Shadow</a></li>
<li data-value="fa-spin"><a>Spin</a></li>
</ul>
</li>
<li><a href="#" class="style">Transform</a></li>
<li><a href="#" class="clear-style">Reset Transformation</a></li>
</div>
</template>
@@ -284,6 +284,8 @@
<script t-if="not translatable" type="text/javascript" src="/website/static/src/js/website.snippets.editor.js"></script>
<script t-if="not translatable" type="text/javascript" src="/website/static/src/js/website.ace.js"></script>
<script t-if="translatable" type="text/javascript" src="/website/static/src/js/website.translator.js"></script>
<script type="text/javascript" src="/website/static/src/js/jQuery.transfo.js"></script>
</xpath>
</template>
@@ -66,39 +66,23 @@
},
{
waitNot: '.product_price .oe_currency_value:containsExact(1.00)',
element: '#wrap img.img:first',
element: '#wrap img.product_detail_img',
placement: 'top',
title: _t("Update image"),
content: _t("Click here to set an image describing your product."),
},
{
element: 'button.hover-edition-button:visible',
element: 'img[alt=ipad]',
placement: 'top',
title: _t("Update image"),
content: _t("Click here to set an image describing your product."),
},
{
wait: 500,
element: '.well a.pull-right',
placement: 'bottom',
title: _t("Select an Image"),
content: _t("Let's select an existing image."),
popover: { fixed: true },
content: _t("Let's select an ipad image."),
},
{
element: 'img[alt=imac]',
placement: 'bottom',
title: _t("Select an Image"),
content: _t("Let's select an imac image."),
popover: { fixed: true },
},
{
waitNot: 'img[alt=imac]',
waitFor: '.media_selected img[alt=ipad]',
element: '.modal-content button.save',
placement: 'bottom',
title: _t("Select this Image"),
content: _t("Click to add the image to the product decsription."),
popover: { fixed: true },
placement: 'top',
title: _t("Save this Image"),
content: _t("Click on save to add the image to the product decsription."),
},
{
waitNot: '.modal-content:visible',