" ).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 $( "
" )[ this.options.html ? "html" : "text" ]( item.label ) )
- .appendTo( ul )
- .addClass(item.classname);
- }
-});
-
-});
diff --git a/addons/web/static/src/js/libs/autocomplete.js b/addons/web/static/src/js/libs/autocomplete.js
new file mode 100644
index 00000000000..72f3ee8911b
--- /dev/null
+++ b/addons/web/static/src/js/libs/autocomplete.js
@@ -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( $( "
" ).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 $( "
" )
+ .data( "item.autocomplete", item )
+ .append( $( "
" )[ this.options.html ? "html" : "text" ]( item.label ) )
+ .appendTo( ul )
+ .addClass(item.classname);
+ },
+});
+});
diff --git a/addons/web/static/src/js/libs/bootstrap.js b/addons/web/static/src/js/libs/bootstrap.js
new file mode 100644
index 00000000000..04ca2381d7d
--- /dev/null
+++ b/addons/web/static/src/js/libs/bootstrap.js
@@ -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);
+};
+});
diff --git a/addons/web/static/src/js/libs/jquery.js b/addons/web/static/src/js/libs/jquery.js
new file mode 100644
index 00000000000..ace99a0f8d3
--- /dev/null
+++ b/addons/web/static/src/js/libs/jquery.js
@@ -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);
+ });
+ });
+ },
+});
+});
diff --git a/addons/web/static/src/js/libs/nvd3.js b/addons/web/static/src/js/libs/nvd3.js
new file mode 100644
index 00000000000..963a1454c3d
--- /dev/null
+++ b/addons/web/static/src/js/libs/nvd3.js
@@ -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;
+};
+});
diff --git a/addons/web/static/src/js/views/form/form_controller.js b/addons/web/static/src/js/views/form/form_controller.js
index 0b85ee8cf42..e9bc8cf2a2a 100644
--- a/addons/web/static/src/js/views/form/form_controller.js
+++ b/addons/web/static/src/js/views/form/form_controller.js
@@ -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();
}
},
/**
diff --git a/addons/web/views/webclient_templates.xml b/addons/web/views/webclient_templates.xml
index 02ddcb28dde..fe23ff89679 100644
--- a/addons/web/views/webclient_templates.xml
+++ b/addons/web/views/webclient_templates.xml
@@ -59,6 +59,9 @@
+
+
+
@@ -136,6 +139,7 @@
+
@@ -171,7 +175,6 @@
-
diff --git a/addons/web_editor/static/src/js/snippets.editor.js b/addons/web_editor/static/src/js/snippets.editor.js
index f68bf8756bb..e11e3205815 100644
--- a/addons/web_editor/static/src/js/snippets.editor.js
+++ b/addons/web_editor/static/src/js/snippets.editor.js
@@ -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 $(); },
diff --git a/addons/web_editor/static/src/js/translator.js b/addons/web_editor/static/src/js/translator.js
index b2e7aa483fb..9d1ebe94082 100644
--- a/addons/web_editor/static/src/js/translator.js
+++ b/addons/web_editor/static/src/js/translator.js
@@ -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
diff --git a/addons/web_tour/static/src/js/tour_manager.js b/addons/web_tour/static/src/js/tour_manager.js
index 829c06e7dc5..26628e57384 100644
--- a/addons/web_tour/static/src/js/tour_manager.js
+++ b/addons/web_tour/static/src/js/tour_manager.js
@@ -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';
}
diff --git a/addons/website_event_track/static/src/js/website_event_track.js b/addons/website_event_track/static/src/js/website_event_track.js
index ccb080270aa..4fb9baa8215 100644
--- a/addons/website_event_track/static/src/js/website_event_track.js
+++ b/addons/website_event_track/static/src/js/website_event_track.js
@@ -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);
}