diff options
| author | Géry Debongnie <ged@odoo.com> | 2017-03-05 10:05:56 +0100 |
|---|---|---|
| committer | Aaron Bohy <aab@odoo.com> | 2017-04-11 19:44:38 +0200 |
| commit | 905e01921f3c3ef43ace6fc537d1d8c0d280002c (patch) | |
| tree | 265c43ab21c5401a5d9f0f3d64d86f1ac417451c /addons/web/static/src/js/framework/misc.js | |
| parent | 54d4c73af4ad05c7640d28c1892247c9538b8017 (diff) | |
[REF] web, *: redesign all JS views
This commit introduce a full redesign of all JS views. We started
basically from scratch. The goal was to unify all the various views
under a common framework, to make them testable, to make then usable in
different conditions (in studio, or in the frontend), and to make our
lives easier.
Some important points are:
- we introduced new coding guidelines (camelCase, 80 chars width, ...)
- we have a brand new testing framework (still QUnit based)
- kanban view moved to the web addon
- calendar view (formerly web_calender) moved to web as well
- the tree view was removed
- all new code should be documented
We hope that this code is the start of a new era for the Odoo web
client, we want to have a high quality codebase, well documented, well
tested, well designed.
Work done by the framework team: mostly aab, ged, chm, dmo, qsm
Diffstat (limited to 'addons/web/static/src/js/framework/misc.js')
| -rw-r--r-- | addons/web/static/src/js/framework/misc.js | 438 |
1 files changed, 0 insertions, 438 deletions
diff --git a/addons/web/static/src/js/framework/misc.js b/addons/web/static/src/js/framework/misc.js deleted file mode 100644 index e083ee25b22..00000000000 --- a/addons/web/static/src/js/framework/misc.js +++ /dev/null @@ -1,438 +0,0 @@ -odoo.define('web.framework', function (require) { -"use strict"; - -var core = require('web.core'); -var crash_manager = require('web.crash_manager'); -var ajax = require('web.ajax'); -var Widget = require('web.Widget'); - -var _t = core._t; - -var messages_by_seconds = function() { - return [ - [0, _t("Loading...")], - [20, _t("Still loading...")], - [60, _t("Still loading...<br />Please be patient.")], - [120, _t("Don't leave yet,<br />it's still loading...")], - [300, _t("You may not believe it,<br />but the application is actually loading...")], - [420, _t("Take a minute to get a coffee,<br />because it's loading...")], - [3600, _t("Maybe you should consider reloading the application by pressing F5...")] - ]; -}; - -var Throbber = Widget.extend({ - template: "Throbber", - start: function() { - this.start_time = new Date().getTime(); - this.act_message(); - }, - act_message: function() { - var self = this; - setTimeout(function() { - if (self.isDestroyed()) - return; - var seconds = (new Date().getTime() - self.start_time) / 1000; - var mes; - _.each(messages_by_seconds(), function(el) { - if (seconds >= el[0]) - mes = el[1]; - }); - self.$(".oe_throbber_message").html(mes); - self.act_message(); - }, 1000); - }, -}); - -/** Setup blockui */ -if ($.blockUI) { - $.blockUI.defaults.baseZ = 1100; - $.blockUI.defaults.message = '<div class="openerp oe_blockui_spin_container" style="background-color: transparent;">'; - $.blockUI.defaults.css.border = '0'; - $.blockUI.defaults.css["background-color"] = ''; -} - - -var throbbers = []; - -function blockUI () { - var tmp = $.blockUI.apply($, arguments); - var throbber = new Throbber(); - throbbers.push(throbber); - throbber.appendTo($(".oe_blockui_spin_container")); - $('body').addClass('o_ui_blocked'); - return tmp; -} - -function unblockUI () { - _.invoke(throbbers, 'destroy'); - throbbers = []; - $('body').removeClass('o_ui_blocked'); - return $.unblockUI.apply($, arguments); -} - -/** - * Redirect to url by replacing window.location - * If wait is true, sleep 1s and wait for the server i.e. after a restart. - */ -function redirect (url, wait) { - // Dont display a dialog if some xmlhttprequest are in progress - crash_manager.disable(); - - var load = function() { - var old = "" + window.location; - var old_no_hash = old.split("#")[0]; - var url_no_hash = url.split("#")[0]; - location.assign(url); - if (old_no_hash === url_no_hash) { - location.reload(true); - } - }; - - var wait_server = function() { - ajax.rpc("/web/webclient/version_info", {}).done(load).fail(function() { - setTimeout(wait_server, 250); - }); - }; - - if (wait) { - setTimeout(wait_server, 1000); - } else { - load(); - } -} - -// * Client action to reload the whole interface. -// * If params.menu_id, it opens the given menu entry. -// * If params.wait, reload will wait the openerp server to be reachable before reloading - -function Reload(parent, action) { - var params = action.params || {}; - var menu_id = params.menu_id || false; - var l = window.location; - - var sobj = $.deparam(l.search.substr(1)); - if (params.url_search) { - sobj = _.extend(sobj, params.url_search); - } - var search = '?' + $.param(sobj); - - var hash = l.hash; - if (menu_id) { - hash = "#menu_id=" + menu_id; - } - var url = l.protocol + "//" + l.host + l.pathname + search + hash; - - redirect(url, params.wait); -} - -core.action_registry.add("reload", Reload); - - -/** - * Client action to go back home. - */ -function Home (parent, action) { - var url = '/' + (window.location.search || ''); - redirect(url, action && action.params && action.params.wait); -} -core.action_registry.add("home", Home); - -/** - * Client action to go back in breadcrumb history. - * If can't go back in history stack, will go back to home. - */ -function HistoryBack (parent) { - parent.history_back().fail(function () { - Home(parent); - }); -} -core.action_registry.add("history_back", HistoryBack); - -function login() { - redirect('/web/login'); -} -core.action_registry.add("login", login); - -function logout() { - redirect('/web/session/logout'); - return $.Deferred(); -} -core.action_registry.add("logout", logout); - -/** - * Client action to refresh the session context (making sure - * HTTP requests will have the right one) then reload the - * whole interface. - */ -function ReloadContext (parent, action) { - // side-effect of get_session_info is to refresh the session context - ajax.rpc("/web/session/get_session_info", {}).then(function() { - Reload(parent, action); - }); -} -core.action_registry.add("reload_context", ReloadContext); - - -// 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.openerpClass = function(additionalClass) { - // This plugin should be applied on top level elements - additionalClass = additionalClass || ''; - if (!!$.browser.msie) { - additionalClass += ' openerp_ie'; - } - return this.each(function() { - $(this).addClass('openerp ' + additionalClass); - }); -}; -$.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, - 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); - } -}); - -/** - * Private function to notify that something has been attached in the DOM - * @param {htmlString or Element or Array or jQuery} [content] the content that - * has been attached in the DOM - * @params {Array} [callbacks] array of {widget: w, callback_args: args} such - * that on_attach_callback() will be called on each w with arguments args - */ -function _notify (content, callbacks) { - _.each(callbacks, function(c) { - if (c.widget && c.widget.on_attach_callback) { - c.widget.on_attach_callback(c.callback_args); - } - }); - core.bus.trigger('DOM_updated', content); -} -/** - * Appends content in a jQuery object and optionnally triggers an event - * @param {jQuery} [$target] the node where content will be appended - * @param {htmlString or Element or Array or jQuery} [content] DOM element, - * array of elements, HTML string or jQuery object to append to $target - * @param {Boolean} [options.in_DOM] true if $target is in the DOM - * @param {Array} [options.callbacks] array of objects describing the callbacks - * to perform (see _notify for a complete description) - */ -function append ($target, content, options) { - $target.append(content); - if (options && options.in_DOM) { - _notify(content, options.callbacks); - } -} -/** - * Prepends content in a jQuery object and optionnally triggers an event - * @param {jQuery} [$target] the node where content will be prepended - * @param {htmlString or Element or Array or jQuery} [content] DOM element, - * array of elements, HTML string or jQuery object to prepend to $target - * @param {Boolean} [options.in_DOM] true if $target is in the DOM - * @param {Array} [options.callbacks] array of objects describing the callbacks - * to perform (see _notify for a complete description) - */ -function prepend ($target, content, options) { - $target.prepend(content); - if (options && options.in_DOM) { - _notify(content, options.callbacks); - } -} - -/** - * Detaches widgets from the DOM and performs their on_detach_callback() - * @param {Array} [to_detach] array of {widget: w, callback_args: args} such - * that w.$el will be detached and w.on_detach_callback(args) will be called - * @param {jQuery} [options.$to_detach] if given, detached instead of widgets' $el - * @return {jQuery} the detached elements - */ -function detach (to_detach, options) { - _.each(to_detach, function(d) { - if (d.widget.on_detach_callback) { - d.widget.on_detach_callback(d.callback_args); - } - }); - var $to_detach = options && options.$to_detach; - if (!$to_detach) { - $to_detach = $(_.map(to_detach, function(d) { - return d.widget.el; - })); - } - return $to_detach.detach(); -} - -/** - * Returns the distance between a DOM element and the top-left corner of the window - * @param {element} [e] the DOM element - * @return {Object} the left and top distances in pixels - */ -function getPosition(e) { - var position = {left: 0, top: 0}; - while (e) { - position.left += e.offsetLeft; - position.top += e.offsetTop; - e = e.offsetParent; - } - return position; -} - -return { - blockUI: blockUI, - unblockUI: unblockUI, - redirect: redirect, - append: append, - prepend: prepend, - detach: detach, - getPosition: getPosition, -}; - -}); - -odoo.define('web.IFrameWidget', function (require) { -"use strict"; - -var Widget = require('web.Widget'); - -/** - * Generic widget to create an iframe that listens for clicks - * - * It should be extended by overwritting the methods: - * init: function(parent) { - * this._super(parent, <url_of_iframe> - * }, - * iframe_clicked: function(e){ - * filter the clicks you want to use and apply - * an action on it - * } - */ -var IFrameWidget = Widget.extend({ - tagName: 'iframe', - init: function(parent, url) { - this._super(parent); - this.url = url; - }, - start: function() { - this.$el.css({height: '100%', width: '100%', border: 0}); - this.$el.attr({src: this.url}); - this.$el.on("load", this.bind_events.bind(this)); - return this._super(); - }, - bind_events: function(){ - this.$el.contents().click(this.iframe_clicked.bind(this)); - }, - iframe_clicked: function(e){ - } -}); - -return IFrameWidget; - -}); |
