[IMP] web, *: reorganize our libraries' extensions
* web_editor, web_tour, website_event_track Before this commit, one JS file was responsible for all the library extensions and fixes. There were two main problems with this system: - The file was only available in the backend (as some extensions are made on backend-only libraries). - Some other modules were doing library customizations. This commit creates one file per library to regroup their associated customization and adds them in the right asset. These are placed in the web module and every other module should avoid doing customizations. This allows to have libraries consistency accross all modules and between the backend and the frontend.
This commit is contained in:
@@ -1,138 +0,0 @@
|
||||
odoo.define('web.libs', function () {
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* External Libraries Customization
|
||||
*
|
||||
* This is the place where we do some slightly crappy libraries customization.
|
||||
* We are not proud of this, but at least, we try to avoid patching them in
|
||||
* place.
|
||||
*
|
||||
* In an ideal world, this file would not be needed, because external libraries
|
||||
* would not have bugs, their APIS would be done in a way that we could use them
|
||||
* as is, and their distribution process would make sure that they are properly
|
||||
* configured. However, we do not live in such a world, so this file is
|
||||
* necessary.
|
||||
*/
|
||||
|
||||
// nvd3 customization
|
||||
//-------------------------------------------------------------------------
|
||||
if ('nv' in window) {
|
||||
nv.dev = false; // sets nvd3 library in production mode
|
||||
|
||||
// monkey patch nvd3 to allow removing eventhandler on windowresize events
|
||||
// see https://github.com/novus/nvd3/pull/396 for more details
|
||||
|
||||
// Adds a resize listener to the window.
|
||||
nv.utils.onWindowResize = function(fun) {
|
||||
if (fun === null) return;
|
||||
window.addEventListener('resize', fun);
|
||||
};
|
||||
|
||||
// Backwards compatibility with current API.
|
||||
nv.utils.windowResize = nv.utils.onWindowResize;
|
||||
|
||||
// Removes a resize listener from the window.
|
||||
nv.utils.offWindowResize = function(fun) {
|
||||
if (fun === null) return;
|
||||
window.removeEventListener('resize', fun);
|
||||
};
|
||||
|
||||
// monkey patch nvd3 to prevent crashes when user changes view and nvd3
|
||||
// tries to remove tooltips after 500 ms... seriously nvd3, what were you
|
||||
// thinking?
|
||||
nv.tooltip.cleanup = function () {
|
||||
$('.nvtooltip').remove();
|
||||
};
|
||||
|
||||
// monkey patch nvd3 to prevent it to display a tooltip (position: absolute)
|
||||
// with a negative `top`; with this patch the highest tooltip's position is
|
||||
// still in the graph
|
||||
var originalCalcTooltipPosition = nv.tooltip.calcTooltipPosition;
|
||||
nv.tooltip.calcTooltipPosition = function () {
|
||||
var container = originalCalcTooltipPosition.apply(this, arguments);
|
||||
container.style.top = container.style.top.split('px')[0] < 0 ? 0 + 'px' : container.style.top;
|
||||
return container;
|
||||
};
|
||||
}
|
||||
|
||||
// Bootstrap customization
|
||||
//-------------------------------------------------------------------------
|
||||
/* Bootstrap defaults overwrite */
|
||||
$.fn.tooltip.Constructor.DEFAULTS.placement = 'auto top';
|
||||
$.fn.tooltip.Constructor.DEFAULTS.html = true;
|
||||
$.fn.tooltip.Constructor.DEFAULTS.trigger = 'hover focus click';
|
||||
$.fn.tooltip.Constructor.DEFAULTS.container = 'body';
|
||||
$.fn.tooltip.Constructor.DEFAULTS.delay = { show: 1000, hide: 0 };
|
||||
//overwrite bootstrap tooltip method to prevent showing 2 tooltip at the same time
|
||||
var bootstrap_show_function = $.fn.tooltip.Constructor.prototype.show;
|
||||
$.fn.modal.Constructor.prototype.enforceFocus = function () { };
|
||||
$.fn.tooltip.Constructor.prototype.show = function () {
|
||||
$('.tooltip').remove();
|
||||
//the following fix the bug when using placement
|
||||
//auto and the parent element does not exist anymore resulting in
|
||||
//an error. This should be remove once we updade bootstrap to a version that fix the bug
|
||||
//edit: bug has been fixed here : https://github.com/twbs/bootstrap/pull/13752
|
||||
var e = $.Event('show.bs.' + this.type);
|
||||
var inDom = $.contains(document.documentElement, this.$element[0]);
|
||||
if (e.isDefaultPrevented() || !inDom) return;
|
||||
return bootstrap_show_function.call(this);
|
||||
};
|
||||
|
||||
// jquery customization
|
||||
//-------------------------------------------------------------------------
|
||||
jQuery.expr[":"].Contains = jQuery.expr.createPseudo(function(arg) {
|
||||
return function( elem ) {
|
||||
return jQuery(elem).text().toUpperCase().indexOf(arg.toUpperCase()) >= 0;
|
||||
};
|
||||
});
|
||||
|
||||
/** Custom jQuery plugins */
|
||||
$.fn.getAttributes = function() {
|
||||
var o = {};
|
||||
if (this.length) {
|
||||
for (var attr, i = 0, attrs = this[0].attributes, l = attrs.length; i < l; i++) {
|
||||
attr = attrs.item(i);
|
||||
o[attr.nodeName] = attr.value;
|
||||
}
|
||||
}
|
||||
return o;
|
||||
};
|
||||
$.fn.openerpBounce = function() {
|
||||
return this.each(function() {
|
||||
$(this).css('box-sizing', 'content-box').effect('bounce', {distance: 18, times: 5}, 250);
|
||||
});
|
||||
};
|
||||
|
||||
// jquery autocomplete tweak to allow html and classnames
|
||||
var proto = $.ui.autocomplete.prototype;
|
||||
var initSource = proto._initSource;
|
||||
|
||||
function filter( array, term ) {
|
||||
var matcher = new RegExp( $.ui.autocomplete.escapeRegex(term), "i" );
|
||||
return $.grep( array, function(value_) {
|
||||
return matcher.test( $( "<div>" ).html( value_.label || value_.value || value_ ).text() );
|
||||
});
|
||||
}
|
||||
|
||||
$.extend( proto, {
|
||||
_initSource: function() {
|
||||
if ( this.options.html && $.isArray(this.options.source) ) {
|
||||
this.source = function( request, response ) {
|
||||
response( filter( this.options.source, request.term ) );
|
||||
};
|
||||
} else {
|
||||
initSource.call( this );
|
||||
}
|
||||
},
|
||||
|
||||
_renderItem: function( ul, item) {
|
||||
return $( "<li></li>" )
|
||||
.data( "item.autocomplete", item )
|
||||
.append( $( "<a></a>" )[ this.options.html ? "html" : "text" ]( item.label ) )
|
||||
.appendTo( ul )
|
||||
.addClass(item.classname);
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
@@ -0,0 +1,38 @@
|
||||
odoo.define('web.autocomplete.extensions', function () {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* The jquery autocomplete library extensions and fixes should be done here to
|
||||
* avoid patching in place.
|
||||
*/
|
||||
|
||||
// jquery autocomplete tweak to allow html and classnames
|
||||
var proto = $.ui.autocomplete.prototype;
|
||||
var initSource = proto._initSource;
|
||||
|
||||
function filter( array, term ) {
|
||||
var matcher = new RegExp( $.ui.autocomplete.escapeRegex(term), "i" );
|
||||
return $.grep( array, function (value_) {
|
||||
return matcher.test( $( "<div>" ).html( value_.label || value_.value || value_ ).text() );
|
||||
});
|
||||
}
|
||||
|
||||
$.extend(proto, {
|
||||
_initSource: function () {
|
||||
if ( this.options.html && $.isArray(this.options.source) ) {
|
||||
this.source = function (request, response) {
|
||||
response( filter( this.options.source, request.term ) );
|
||||
};
|
||||
} else {
|
||||
initSource.call( this );
|
||||
}
|
||||
},
|
||||
_renderItem: function (ul, item) {
|
||||
return $( "<li></li>" )
|
||||
.data( "item.autocomplete", item )
|
||||
.append( $( "<a></a>" )[ this.options.html ? "html" : "text" ]( item.label ) )
|
||||
.appendTo( ul )
|
||||
.addClass(item.classname);
|
||||
},
|
||||
});
|
||||
});
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
odoo.define('web.bootstrap.extensions', function () {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* The bootstrap library extensions and fixes should be done here to avoid
|
||||
* patching in place.
|
||||
*/
|
||||
|
||||
/* Bootstrap defaults overwrite */
|
||||
$.fn.tooltip.Constructor.DEFAULTS.placement = 'auto top';
|
||||
$.fn.tooltip.Constructor.DEFAULTS.html = true;
|
||||
$.fn.tooltip.Constructor.DEFAULTS.trigger = 'hover focus click';
|
||||
$.fn.tooltip.Constructor.DEFAULTS.container = 'body';
|
||||
$.fn.tooltip.Constructor.DEFAULTS.delay = { show: 1000, hide: 0 };
|
||||
//overwrite bootstrap tooltip method to prevent showing 2 tooltip at the same time
|
||||
var bootstrap_show_function = $.fn.tooltip.Constructor.prototype.show;
|
||||
$.fn.modal.Constructor.prototype.enforceFocus = function () { };
|
||||
$.fn.tooltip.Constructor.prototype.show = function () {
|
||||
$('.tooltip').remove();
|
||||
//the following fix the bug when using placement
|
||||
//auto and the parent element does not exist anymore resulting in
|
||||
//an error. This should be remove once we updade bootstrap to a version that fix the bug
|
||||
//edit: bug has been fixed here : https://github.com/twbs/bootstrap/pull/13752
|
||||
var e = $.Event('show.bs.' + this.type);
|
||||
var inDom = $.contains(document.documentElement, this.$element[0]);
|
||||
if (e.isDefaultPrevented() || !inDom) return;
|
||||
return bootstrap_show_function.call(this);
|
||||
};
|
||||
});
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
odoo.define('web.jquery.extensions', function () {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* The jquery library extensions and fixes should be done here to avoid patching
|
||||
* in place.
|
||||
*/
|
||||
|
||||
// jQuery selectors extensions
|
||||
$.extend($.expr[':'], {
|
||||
containsLike: function (element, index, matches){
|
||||
return element.innerHTML.toUpperCase().indexOf(matches[3].toUpperCase()) >= 0;
|
||||
},
|
||||
containsExact: function (element, index, matches){
|
||||
return $.trim(element.innerHTML) === matches[3];
|
||||
},
|
||||
/**
|
||||
* Note all escaped characters need to be double escaped inside of the
|
||||
* expression, so "\(" needs to be "\\("
|
||||
*/
|
||||
containsRegex: function (element, index, matches){
|
||||
var regreg = /^\/((?:\\\/|[^\/])+)\/([mig]{0,3})$/,
|
||||
reg = regreg.exec(matches[3]);
|
||||
return reg ? new RegExp(reg[1], reg[2]).test($.trim(element.innerHTML)) : false;
|
||||
},
|
||||
propChecked: function (element, index, matches) {
|
||||
return $(element).prop("checked") === true;
|
||||
},
|
||||
propSelected: function (element, index, matches) {
|
||||
return $(element).prop("selected") === true;
|
||||
},
|
||||
propValue: function (element, index, matches) {
|
||||
return $(element).prop("value") === matches[3];
|
||||
},
|
||||
propValueContains: function (element, index, matches) {
|
||||
return $(element).prop("value") && $(element).prop("value").indexOf(matches[3]) !== -1;
|
||||
},
|
||||
hasData: function (element) {
|
||||
return !!_.toArray(element.dataset).length;
|
||||
},
|
||||
data: function (element, index, matches) {
|
||||
return $(element).data(matches[3]);
|
||||
},
|
||||
});
|
||||
|
||||
// jQuery functions extensions
|
||||
$.fn.extend({
|
||||
/**
|
||||
* Returns all the attributes of a DOM element (first one in the jQuery
|
||||
* set).
|
||||
*
|
||||
* @returns {Object} attribute name -> attribute value
|
||||
*/
|
||||
getAttributes: function () {
|
||||
var o = {};
|
||||
if (this.length) {
|
||||
var attrs = this[0].attributes;
|
||||
for (var i = 0, l = attrs.length ; i < l ; i++) {
|
||||
var attr = attrs.item(i);
|
||||
o[attr.name] = attr.value;
|
||||
}
|
||||
}
|
||||
return o;
|
||||
},
|
||||
/**
|
||||
* Makes DOM elements bounce the way Odoo decided it.
|
||||
*/
|
||||
odooBounce: function () {
|
||||
return this.each(function () {
|
||||
var $elem = $(this);
|
||||
$elem
|
||||
.css('box-sizing', 'content-box')
|
||||
.effect('bounce', {distance: 18, times: 5}, 250, function () {
|
||||
$elem.css('box-sizing', '');
|
||||
});
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Allows to bind events to a handler just as the standard `$.on` function
|
||||
* but binds the handler so that it is executed before any already-attached
|
||||
* handler for the same events.
|
||||
*
|
||||
* @see jQuery.on
|
||||
*/
|
||||
prependEvent: function (events, selector, data, handler) {
|
||||
this.on.apply(this, arguments);
|
||||
|
||||
events = events.split(' ');
|
||||
return this.each(function () {
|
||||
var el = this;
|
||||
_.each(events, function (evName) {
|
||||
var handler = $._data(el, 'events')[evName].pop();
|
||||
$._data(el, 'events')[evName].unshift(handler);
|
||||
});
|
||||
});
|
||||
},
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,49 @@
|
||||
odoo.define('web.nvd3.extensions', function () {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* The nvd3 library extensions and fixes should be done here to avoid patching
|
||||
* in place.
|
||||
*/
|
||||
|
||||
if (!('nv' in window)) {
|
||||
return;
|
||||
}
|
||||
|
||||
nv.dev = false; // sets nvd3 library in production mode
|
||||
|
||||
// monkey patch nvd3 to allow removing eventhandler on windowresize events
|
||||
// see https://github.com/novus/nvd3/pull/396 for more details
|
||||
|
||||
// Adds a resize listener to the window.
|
||||
nv.utils.onWindowResize = function (fun) {
|
||||
if (fun === null) return;
|
||||
window.addEventListener('resize', fun);
|
||||
};
|
||||
|
||||
// Backwards compatibility with current API.
|
||||
nv.utils.windowResize = nv.utils.onWindowResize;
|
||||
|
||||
// Removes a resize listener from the window.
|
||||
nv.utils.offWindowResize = function (fun) {
|
||||
if (fun === null) return;
|
||||
window.removeEventListener('resize', fun);
|
||||
};
|
||||
|
||||
// monkey patch nvd3 to prevent crashes when user changes view and nvd3
|
||||
// tries to remove tooltips after 500 ms... seriously nvd3, what were you
|
||||
// thinking?
|
||||
nv.tooltip.cleanup = function () {
|
||||
$('.nvtooltip').remove();
|
||||
};
|
||||
|
||||
// monkey patch nvd3 to prevent it to display a tooltip (position: absolute)
|
||||
// with a negative `top`; with this patch the highest tooltip's position is
|
||||
// still in the graph
|
||||
var originalCalcTooltipPosition = nv.tooltip.calcTooltipPosition;
|
||||
nv.tooltip.calcTooltipPosition = function () {
|
||||
var container = originalCalcTooltipPosition.apply(this, arguments);
|
||||
container.style.top = container.style.top.split('px')[0] < 0 ? 0 + 'px' : container.style.top;
|
||||
return container;
|
||||
};
|
||||
});
|
||||
@@ -339,7 +339,7 @@ var FormController = BasicController.extend({
|
||||
*/
|
||||
_onBounceEdit: function () {
|
||||
if (this.$buttons) {
|
||||
this.$buttons.find('.o_form_button_edit').openerpBounce();
|
||||
this.$buttons.find('.o_form_button_edit').odooBounce();
|
||||
}
|
||||
},
|
||||
/**
|
||||
|
||||
@@ -59,6 +59,9 @@
|
||||
|
||||
<script type="text/javascript" src="/web/static/lib/qweb/qweb2.js"></script>
|
||||
<script type="text/javascript" src="/web/static/src/js/boot.js"></script>
|
||||
<script type="text/javascript" src="/web/static/src/js/libs/autocomplete.js"></script>
|
||||
<script type="text/javascript" src="/web/static/src/js/libs/bootstrap.js"></script>
|
||||
<script type="text/javascript" src="/web/static/src/js/libs/jquery.js"></script>
|
||||
<script type="text/javascript" src="/web/static/src/js/services/config.js"></script>
|
||||
<script type="text/javascript" src="/web/static/src/js/core/abstract_service.js"></script>
|
||||
<script type="text/javascript" src="/web/static/src/js/core/class.js"></script>
|
||||
@@ -136,6 +139,7 @@
|
||||
<!-- Special case: core.js declares $.browser needed by ba-bbq -->
|
||||
<script type="text/javascript" src="/web/static/lib/jquery.ba-bbq/jquery.ba-bbq.js"></script>
|
||||
|
||||
<script type="text/javascript" src="/web/static/src/js/libs/nvd3.js"></script>
|
||||
<script type="text/javascript" src="/web/static/src/js/core/domain.js"></script>
|
||||
<script type="text/javascript" src="/web/static/src/js/core/pyeval.js"></script>
|
||||
<script type="text/javascript" src="/web/static/src/js/chrome/action_manager.js"></script>
|
||||
@@ -171,7 +175,6 @@
|
||||
<script type="text/javascript" src="/web/static/src/js/chrome/search_inputs.js"></script>
|
||||
<script type="text/javascript" src="/web/static/src/js/chrome/search_menus.js"></script>
|
||||
<script type="text/javascript" src="/web/static/src/js/apps.js"></script>
|
||||
<script type="text/javascript" src="/web/static/src/js/libs.js"></script>
|
||||
|
||||
<script type="text/javascript" src="/web/static/src/js/fields/abstract_field.js"></script>
|
||||
<script type="text/javascript" src="/web/static/src/js/fields/basic_fields.js"></script>
|
||||
|
||||
@@ -18,15 +18,6 @@ var data = {};
|
||||
|
||||
/* ----- SNIPPET SELECTOR ---- */
|
||||
|
||||
$.extend($.expr[':'], {
|
||||
hasData: function (node) {
|
||||
return !!_.toArray(node.dataset).length;
|
||||
},
|
||||
data: function (node, i, m) {
|
||||
return $(node).data(m[3]);
|
||||
}
|
||||
});
|
||||
|
||||
data.globalSelector = {
|
||||
closest: function () { return $(); },
|
||||
all: function () { return $(); },
|
||||
|
||||
@@ -13,21 +13,6 @@ var _t = core._t;
|
||||
var translatable = !!$('html').data('translatable');
|
||||
var edit_translations = !!$('html').data('edit_translations');
|
||||
|
||||
$.fn.extend({
|
||||
prependEvent: function (events, selector, data, handler) {
|
||||
this.on(events, selector, data, handler);
|
||||
events = events.split(' ');
|
||||
this.each(function () {
|
||||
var el = this;
|
||||
_.each(events, function (event) {
|
||||
var handler = $._data(el, 'events')[event].pop();
|
||||
$._data(el, 'events')[event].unshift(handler);
|
||||
});
|
||||
});
|
||||
return this;
|
||||
}
|
||||
});
|
||||
|
||||
var RTE_Translate = rte.Class.extend({
|
||||
saveElement: function ($el, context) {
|
||||
// remove multi edition
|
||||
|
||||
@@ -12,34 +12,6 @@ var _t = core._t;
|
||||
|
||||
var RUNNING_TOUR_TIMEOUT = 10000;
|
||||
|
||||
$.extend($.expr[':'],{
|
||||
containsExact: function(element, index, matches){
|
||||
return $.trim(element.innerHTML.toLowerCase()) === matches[3].toLowerCase();
|
||||
},
|
||||
containsExactCase: function(element, index, matches){
|
||||
return $.trim(element.innerHTML) === matches[3];
|
||||
},
|
||||
// Note all escaped characters need to be double escaped
|
||||
// inside of the containsRegex, so "\(" needs to be "\\("
|
||||
containsRegex: function(element, index, matches){
|
||||
var regreg = /^\/((?:\\\/|[^\/])+)\/([mig]{0,3})$/,
|
||||
reg = regreg.exec(matches[3]);
|
||||
return reg ? new RegExp(reg[1], reg[2]).test($.trim(element.innerHTML)) : false;
|
||||
},
|
||||
propChecked: function(element, index, matches) {
|
||||
return $(element).prop("checked") === true;
|
||||
},
|
||||
propSelected: function(element, index, matches) {
|
||||
return $(element).prop("selected") === true;
|
||||
},
|
||||
propValue: function(element, index, matches) {
|
||||
return $(element).prop("value") === matches[3];
|
||||
},
|
||||
propValueContains: function(element, index, matches) {
|
||||
return $(element).prop("value") && $(element).prop("value").indexOf(matches[3]) !== -1;
|
||||
},
|
||||
});
|
||||
|
||||
function get_step_key(name) {
|
||||
return 'tour_' + name + '_step';
|
||||
}
|
||||
|
||||
@@ -9,8 +9,8 @@ $(document).ready(function() {
|
||||
|
||||
$("#search_summary").removeClass('invisible');
|
||||
if (change_text) {
|
||||
$("#search_number").text($(".event_track:Contains("+change_text+")").length);
|
||||
$(".event_track:not(:Contains("+change_text+"))").addClass('invisible');
|
||||
$("#search_number").text($(".event_track:containsLike("+change_text+")").length);
|
||||
$(".event_track:not(:containsLike("+change_text+"))").addClass('invisible');
|
||||
} else {
|
||||
$("#search_number").text(30);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user