1/** 2 * The jquery library extensions and fixes should be done here to avoid patching 3 * in place. 4 */ 5 6// jQuery selectors extensions 7$.extend($.expr[':'], { 8 data: function (element, index, matches) { 9 return $(element).data(matches[3]); 10 }, 11}); 12 13// jQuery functions extensions 14$.fn.extend({ 15 /** 16 * Makes DOM elements bounce the way Odoo decided it. 17 * 18 * @param {string} [extraClass] 19 */ 20 odooBounce: function (extraClass) { 21 for (const el of this) { 22 el.classList.add('o_catch_attention', extraClass); 23 setTimeout(() => el.classList.remove('o_catch_attention', extraClass), 400); 24 } 25 return this; 26 }, 27 /** 28 * Allows to bind events to a handler just as the standard `$.on` function 29 * but binds the handler so that it is executed before any already-attached 30 * handler for the same events. 31 * 32 * @see jQuery.on 33 */ 34 prependEvent: function (events, selector, data, handler) { 35 this.on.apply(this, arguments); 36 37 events = events.split(' '); 38 return this.each(function () { 39 var el = this; 40 events.forEach((evNameNamespaced) => { 41 var evName = evNameNamespaced.split('.')[0]; 42 var handler = $._data(el, 'events')[evName].pop(); 43 $._data(el, 'events')[evName].unshift(handler); 44 }); 45 }); 46 }, 47 /** 48 * @deprecated this will soon be removed: just rely on the fact that the 49 * scrollbar is at its natural position. 50 * @returns {jQuery} 51 */ 52 getScrollingElement(document = window.document) { 53 const $baseScrollingElement = $(document.scrollingElement); 54 if ($baseScrollingElement.isScrollable() 55 && $baseScrollingElement.hasScrollableContent()) { 56 return $baseScrollingElement; 57 } 58 const bodyHeight = $(document.body).height(); 59 for (const el of document.body.children) { 60 // Search for a body child which is at least as tall as the body 61 // and which has the ability to scroll if enough content in it. If 62 // found, suppose this is the top scrolling element. 63 if (bodyHeight - el.scrollHeight > 1.5) { 64 continue; 65 } 66 const $el = $(el); 67 if ($el.isScrollable()) { 68 return $el; 69 } 70 } 71 return $baseScrollingElement; 72 }, 73 /** 74 * @deprecated this will soon be removed: just rely on the fact that the 75 * scrollbar is at its natural position. 76 * @returns {jQuery} 77 */ 78 getScrollingTarget(contextItem = window.document) { 79 // Cannot use `instanceof` because of cross-frame issues. 80 const isElement = obj => obj && obj.nodeType === Node.ELEMENT_NODE; 81 const isJQuery = obj => obj && ('jquery' in obj); 82 83 const $scrollingElement = isElement(contextItem) 84 ? $(contextItem) 85 : isJQuery(contextItem) 86 ? contextItem 87 : $().getScrollingElement(contextItem); 88 const document = $scrollingElement[0].ownerDocument; 89 return $scrollingElement.is(document.scrollingElement) 90 ? $(document.defaultView) 91 : $scrollingElement; 92 }, 93 /** 94 * @return {boolean} 95 */ 96 hasScrollableContent() { 97 return this[0].scrollHeight > this[0].clientHeight; 98 }, 99 /** 100 * @returns {boolean} 101 */ 102 isScrollable() { 103 if (!this.length) { 104 return false; 105 } 106 const overflow = this.css('overflow-y'); 107 const el = this[0]; 108 return overflow === 'auto' || overflow === 'scroll' 109 || (overflow === 'visible' && el === el.ownerDocument.scrollingElement); 110 }, 111}); 112 113// jQuery functions monkey-patching 114 115// Some magic to ensure scrollTop and animate on html/body animate the top level 116// scrollable element even if not html or body. Note: we should consider 117// removing this as it was only really needed when the #wrapwrap was the one 118// with the scrollbar. Although the rest of the code still use 119// getScrollingElement to be generic so this is consistent. Maybe all of this 120// can live on as long as we continue using jQuery a lot. We can decide of the 121// fate of getScrollingElement and related code the moment we get rid of jQuery. 122const originalScrollTop = $.fn.scrollTop; 123$.fn.scrollTop = function (value) { 124 if (value !== undefined && this.filter('html, body').length) { 125 // The caller wants to scroll a set of elements including html and/or 126 // body to a specific point -> do that but make sure to add the real 127 // top level element to that set of elements if any different is found. 128 const $withRealScrollable = this.not('html, body').add($().getScrollingElement(this[0].ownerDocument)); 129 originalScrollTop.apply($withRealScrollable, arguments); 130 return this; 131 } else if (value === undefined && this.eq(0).is('html, body')) { 132 // The caller wants to get the scroll point of a set of elements, jQuery 133 // will return the scroll point of the first one, if it is html or body 134 // return the scroll point of the real top level element. 135 return originalScrollTop.apply($().getScrollingElement(this[0].ownerDocument), arguments); 136 } 137 return originalScrollTop.apply(this, arguments); 138}; 139const originalAnimate = $.fn.animate; 140$.fn.animate = function (properties, ...rest) { 141 const props = Object.assign({}, properties); 142 if ('scrollTop' in props && this.filter('html, body').length) { 143 // The caller wants to scroll a set of elements including html and/or 144 // body to a specific point -> do that but make sure to add the real 145 // top level element to that set of elements if any different is found. 146 const $withRealScrollable = this.not('html, body').add($().getScrollingElement(this[0].ownerDocument)); 147 originalAnimate.call($withRealScrollable, {'scrollTop': props['scrollTop']}, ...rest); 148 delete props['scrollTop']; 149 } 150 if (!Object.keys(props).length) { 151 return this; 152 } 153 return originalAnimate.call(this, props, ...rest); 154};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.