summaryrefslogtreecommitdiff
path: root/addons/web_editor/static/src/js/editor/transcoder.js
diff options
context:
space:
mode:
Diffstat (limited to 'addons/web_editor/static/src/js/editor/transcoder.js')
-rw-r--r--addons/web_editor/static/src/js/editor/transcoder.js166
1 files changed, 100 insertions, 66 deletions
diff --git a/addons/web_editor/static/src/js/editor/transcoder.js b/addons/web_editor/static/src/js/editor/transcoder.js
index 6b42e028b3a..11d23bf603b 100644
--- a/addons/web_editor/static/src/js/editor/transcoder.js
+++ b/addons/web_editor/static/src/js/editor/transcoder.js
@@ -4,39 +4,49 @@ odoo.define('web_editor.transcoder', function (require) {
var widget = require('web_editor.widget');
var rulesCache = [];
-var getMatchedCSSRules = function (a) {
+
+/**
+ * Returns the css rules which applies on an element, tweaked so that they are
+ * browser/mail client ok.
+ *
+ * @param {DOMElement} a
+ * @returns {Object} css property name -> css property value
+ */
+function getMatchedCSSRules(a) {
+ var i, r, k;
if (!rulesCache.length) {
var sheets = document.styleSheets;
- for(var i = sheets.length-1; i >= 0 ; i--) {
+ for (i = sheets.length-1 ; i >= 0 ; i--) {
var rules;
if (sheets[i].rules) {
rules = sheets[i].rules;
} else {
- //try...catch because Firefox not able to enumerate document.styleSheets[].cssRules[] for cross-domain stylesheets.
+ // try...catch because Firefox not able to enumerate
+ // document.styleSheets[].cssRules[] for cross-domain sheets.
try {
rules = sheets[i].cssRules;
- } catch(e) {
+ } catch (e) {
console.warn("Can't read the css rules of: " + sheets[i].href, e);
continue;
}
rules = sheets[i].cssRules;
}
if (rules) {
- for(var r = rules.length-1; r >= 0; r--) {
+ for (r = rules.length-1; r >= 0; r--) {
var selectorText = rules[r].selectorText;
if (selectorText &&
rules[r].cssText &&
- selectorText !== "*" &&
- selectorText.indexOf(":hover") === -1 &&
- selectorText.indexOf(":before") === -1 &&
- selectorText.indexOf(":after") === -1 &&
- selectorText.indexOf(":active") === -1 &&
- selectorText.indexOf(":link") === -1 &&
- selectorText.indexOf("::") === -1 &&
- selectorText.indexOf("\"") === -1 &&
+ selectorText !== '*' &&
+ selectorText.indexOf(':hover') === -1 &&
+ selectorText.indexOf(':before') === -1 &&
+ selectorText.indexOf(':after') === -1 &&
+ selectorText.indexOf(':active') === -1 &&
+ selectorText.indexOf(':link') === -1 &&
+ selectorText.indexOf('::') === -1 &&
+ selectorText.indexOf('"') === -1 &&
selectorText.indexOf("'") === -1) {
var st = selectorText.split(/\s*,\s*/);
- for (var k=0; k<st.length; k++) {
+ for (k = 0 ; k < st.length ; k++) {
rulesCache.push({ 'selector': st[k], 'style': rules[r].style });
}
}
@@ -47,13 +57,15 @@ var getMatchedCSSRules = function (a) {
}
var css = [];
+ var style;
a.matches = a.matches || a.webkitMatchesSelector || a.mozMatchesSelector || a.msMatchesSelector || a.oMatchesSelector;
- for(var r = 0; r < rulesCache.length; r++) {
+ for (r = 0; r < rulesCache.length; r++) {
if (a.matches(rulesCache[r].selector)) {
- var style = rulesCache[r].style;
+ style = rulesCache[r].style;
if (style.parentRule) {
var style_obj = {};
- for (var k=0, len=style.length; k<len; k++) {
+ var len;
+ for (k = 0, len = style.length ; k < len ; k++) {
if (style[k].indexOf('animation') !== -1) {
continue;
}
@@ -68,19 +80,19 @@ var getMatchedCSSRules = function (a) {
}
}
- function specificity (selector) {
+ function specificity(selector) {
// http://www.w3.org/TR/css3-selectors/#specificity
var a = 0;
- selector = selector.replace(/#[a-z0-9_-]+/gi, function () { a++; return ""; });
+ selector = selector.replace(/#[a-z0-9_-]+/gi, function () { a++; return ''; });
var b = 0;
- selector = selector.replace(/(\.[a-z0-9_-]+)|(\[.*?\])/gi, function () { b++; return ""; });
+ selector = selector.replace(/(\.[a-z0-9_-]+)|(\[.*?\])/gi, function () { b++; return ''; });
var c = 0;
- selector = selector.replace(/(^|\s+|:+)[a-z0-9_-]+/gi, function (a) { if(a.indexOf(':not(')===-1) c++; return ""; });
+ selector = selector.replace(/(^|\s+|:+)[a-z0-9_-]+/gi, function (a) { if (a.indexOf(':not(')===-1) c++; return ''; });
return a*100 + b*10 + c;
}
css.sort(function (a, b) { return specificity(a[0]) - specificity(b[0]); });
- var style = {};
+ style = {};
_.each(css, function (v,k) {
_.each(v[1], function (v,k) {
if (v && _.isString(v) && k.indexOf('-webkit') === -1 && (!style[k] || style[k].indexOf('important') === -1 || v.indexOf('important') !== -1)) {
@@ -99,7 +111,7 @@ var getMatchedCSSRules = function (a) {
delete style.display;
}
- _.each(['margin', 'padding'], function(p) {
+ _.each(['margin', 'padding'], function (p) {
if (style[p+'-top'] || style[p+'-right'] || style[p+'-bottom'] || style[p+'-left']) {
if (style[p+'-top'] === style[p+'-right'] && style[p+'-top'] === style[p+'-bottom'] && style[p+'-top'] === style[p+'-left']) {
// keep => property: [top/right/bottom/left value];
@@ -132,103 +144,125 @@ var getMatchedCSSRules = function (a) {
}
return style;
-};
+}
-// convert font awsome into image
-var font_to_img = function ($editable) {
- $editable.find(".fa").each(function () {
+/**
+ * Converts font icons to images.
+ *
+ * @param {jQuery} $editable - the element in which the font icons have to be
+ * converted to images
+ */
+function fontToImg($editable) {
+ $editable.find('.fa').each(function () {
var $font = $(this);
var icon, content;
_.find(widget.fontIcons, function (font) {
return _.find(widget.getCssSelectors(font.parser), function (css) {
if ($font.is(css[0].replace(/::?before/g, ''))) {
- icon = css[2].split("-").shift();
+ icon = css[2].split('-').shift();
content = css[1].match(/content:\s*['"]?(.)['"]?/)[1];
return true;
}
});
});
if (content) {
- var color = $font.css("color").replace(/\s/g, '');
- $font.replaceWith($("<img/>", {
- "src": _.str.sprintf('/web_editor/font_to_img/%s/%s/%s', content.charCodeAt(0), window.encodeURI(color), Math.max(1, $font.height())),
- "data-class": $font.attr("class"),
- "data-style": $font.attr("style"),
- "class": $font.attr("class").replace(new RegExp("(^|\\s+)" + icon + "(-[^\\s]+)?", "gi"), ''), // remove inline font-awsome style
- "style": $font.attr("style")
- }).css({height: "auto", width: "auto"}));
+ var color = $font.css('color').replace(/\s/g, '');
+ $font.replaceWith($('<img/>', {
+ src: _.str.sprintf('/web_editor/font_to_img/%s/%s/%s', content.charCodeAt(0), window.encodeURI(color), Math.max(1, $font.height())),
+ 'data-class': $font.attr('class'),
+ 'data-style': $font.attr('style'),
+ class: $font.attr('class').replace(new RegExp('(^|\\s+)' + icon + '(-[^\\s]+)?', 'gi'), ''), // remove inline font-awsome style
+ style: $font.attr('style'),
+ }).css({height: 'auto', width: 'auto'}));
} else {
$font.remove();
}
});
-};
-// convert image into font awsome
-var img_to_font = function ($editable) {
- $editable.find("img[src*='/web_editor/font_to_img/']").each(function () {
+}
+
+/**
+ * Converts images which were the result of a font icon convertion to a font
+ * icon again.
+ *
+ * @param {jQuery} $editable - the element in which the images will be converted
+ * back to font icons
+ */
+function imgToFont($editable) {
+ $editable.find('img[src*="/web_editor/font_to_img/"]').each(function () {
var $img = $(this);
- $img.replaceWith($("<span/>", {
- "class": $img.data("class"),
- "style": $img.data("style")
+ $img.replaceWith($('<span/>', {
+ class: $img.data('class'),
+ style: $img.data('style')
}));
});
-};
+}
-// convert class into inline style to send by mail
-var class_to_style = function ($editable) {
+/**
+ * Converts css style to inline style (leave the classes on elements but forces
+ * the style they give as inline style).
+ *
+ * @param {jQuery} $editable
+ */
+function classToStyle($editable) {
if (!rulesCache.length) {
getMatchedCSSRules($editable[0]);
}
$editable.find('*').each(function () {
var $target = $(this);
var css = getMatchedCSSRules(this);
- var style = $target.attr("style") || "";
+ var style = $target.attr('style') || '';
_.each(css, function (v,k) {
if (!(new RegExp('(^|;)\s*' + k).test(style))) {
- style = k+":"+v+";"+style;
+ style = k+':'+v+';'+style;
}
});
if (_.isEmpty(style)) {
- $target.removeAttr("style");
+ $target.removeAttr('style');
} else {
- $target.attr("style", style);
+ $target.attr('style', style);
}
});
-};
-// convert style into inline class from mail
-var style_to_class = function ($editable) {
+}
+
+/**
+ * Removes the inline style which is not necessary (because, for example, a
+ * class on an element will induce the same style).
+ *
+ * @param {jQuery} $editable
+ */
+function styleToClass($editable) {
getMatchedCSSRules($editable[0]);
- var $c = $('<span/>').appendTo("body");
+ var $c = $('<span/>').appendTo(document.body);
$editable.find('*').each(function () {
var $target = $(this);
var css = getMatchedCSSRules(this);
- var style = "";
+ var style = '';
_.each(css, function (v,k) {
if (!(new RegExp('(^|;)\s*' + k).test(style))) {
- style = k+":"+v+";"+style;
+ style = k+':'+v+';'+style;
}
});
- css = ($c.attr("style", style).attr("style") || "").split(/\s*;\s*/);
- style = $target.attr("style") || "";
+ css = ($c.attr('style', style).attr('style') || '').split(/\s*;\s*/);
+ style = $target.attr('style') || '';
_.each(css, function (v) {
style = style.replace(v, '');
});
style = style.replace(/;+(\s;)*/g, ';').replace(/^;/g, '');
if (style !== '') {
- $target.attr("style", style);
+ $target.attr('style', style);
} else {
- $target.removeAttr("style");
+ $target.removeAttr('style');
}
});
$c.remove();
-};
+}
return {
- 'font_to_img': font_to_img,
- 'img_to_font': img_to_font,
- 'class_to_style': class_to_style,
- 'style_to_class': style_to_class,
+ fontToImg: fontToImg,
+ imgToFont: imgToFont,
+ classToStyle: classToStyle,
+ styleToClass: styleToClass,
};
-
});