summaryrefslogtreecommitdiff
path: root/addons/web/static/src/js/core/dom.js
diff options
context:
space:
mode:
authorGéry Debongnie <ged@odoo.com>2017-03-05 10:05:56 +0100
committerAaron Bohy <aab@odoo.com>2017-04-11 19:44:38 +0200
commit905e01921f3c3ef43ace6fc537d1d8c0d280002c (patch)
tree265c43ab21c5401a5d9f0f3d64d86f1ac417451c /addons/web/static/src/js/core/dom.js
parent54d4c73af4ad05c7640d28c1892247c9538b8017 (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/core/dom.js')
-rw-r--r--addons/web/static/src/js/core/dom.js164
1 files changed, 164 insertions, 0 deletions
diff --git a/addons/web/static/src/js/core/dom.js b/addons/web/static/src/js/core/dom.js
new file mode 100644
index 00000000000..4333061f924
--- /dev/null
+++ b/addons/web/static/src/js/core/dom.js
@@ -0,0 +1,164 @@
+odoo.define('web.dom', function (require) {
+"use strict";
+
+/**
+ * DOM Utility helpers
+ *
+ * We collect in this file some helpers to help integrate various DOM
+ * functionalities with the odoo framework. A common theme in these functions
+ * is the use of the main core.bus, which helps the framework react when
+ * something happens in the DOM.
+ */
+
+var core = require('web.core');
+
+/**
+ * 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);
+}
+
+return {
+ /**
+ * 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)
+ */
+ append: function ($target, content, options) {
+ $target.append(content);
+ if (options && options.in_DOM) {
+ _notify(content, options.callbacks);
+ }
+ },
+ /**
+ * Autoresize a $textarea node, by recomputing its height when necessary
+ * @param {number} [options.min_height] by default, 50.
+ * @param {Widget} [options.parent] if set, autoresize will listen to some
+ * extra events to decide when to resize itself. This is useful for
+ * widgets that are not in the dom when the autoresize is declared.
+ */
+ autoresize: function ($textarea, options) {
+ if ($textarea.data("auto_resize")) {
+ return;
+ }
+ function resize () {
+ var heightOffset;
+ var style = window.getComputedStyle($textarea[0], null);
+ if (style.boxSizing === 'content-box') {
+ heightOffset = -(parseFloat(style.paddingTop) + parseFloat(style.paddingBottom));
+ } else {
+ heightOffset = parseFloat(style.borderTopWidth) + parseFloat(style.borderBottomWidth);
+ }
+ $fixed_text_area.width($textarea.width());
+ $fixed_text_area.val($textarea.val());
+ var height = $fixed_text_area[0].scrollHeight;
+ $textarea.css({height: Math.max(height + heightOffset, min_height)});
+ }
+
+ options = options || {};
+
+ var $fixed_text_area;
+ var min_height = (options && options.min_height) || 50;
+ if (!$fixed_text_area) {
+ $fixed_text_area = $('<textarea disabled>').css({
+ position: 'absolute',
+ opacity: 0,
+ height: 10,
+ top: -10000,
+ left: -10000,
+ });
+ $fixed_text_area.addClass($textarea[0].className);
+ $fixed_text_area.insertAfter($textarea);
+ $fixed_text_area.data("auto_resize", true);
+ }
+
+ var style = window.getComputedStyle($textarea[0], null);
+ if (style.resize === 'vertical') {
+ $textarea[0].style.resize = 'none';
+ } else if (style.resize === 'both') {
+ $textarea[0].style.resize = 'horizontal';
+ }
+ resize();
+ $textarea.data("auto_resize", true);
+
+ $textarea.on('input focus', resize);
+ if (options.parent) {
+ core.bus.on('DOM_updated', options.parent, resize);
+ core.bus.on('view_shown', options.parent, resize);
+ }
+
+ },
+ /**
+ * 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
+ */
+ detach: function (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
+ */
+ getPosition: function (e) {
+ var position = {left: 0, top: 0};
+ while (e) {
+ position.left += e.offsetLeft;
+ position.top += e.offsetTop;
+ e = e.offsetParent;
+ }
+ return position;
+ },
+ /**
+ * 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)
+ */
+ prepend: function ($target, content, options) {
+ $target.prepend(content);
+ if (options && options.in_DOM) {
+ _notify(content, options.callbacks);
+ }
+ },
+};
+
+});