summaryrefslogtreecommitdiff
path: root/addons/web/static/src/js/framework/ajax.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/framework/ajax.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/framework/ajax.js')
-rw-r--r--addons/web/static/src/js/framework/ajax.js399
1 files changed, 0 insertions, 399 deletions
diff --git a/addons/web/static/src/js/framework/ajax.js b/addons/web/static/src/js/framework/ajax.js
deleted file mode 100644
index dee6f4599b4..00000000000
--- a/addons/web/static/src/js/framework/ajax.js
+++ /dev/null
@@ -1,399 +0,0 @@
-odoo.define('web.ajax', function (require) {
-"use strict";
-
-var core = require('web.core');
-var utils = require('web.utils');
-var time = require('web.time');
-
-function genericJsonRpc (fct_name, params, fct) {
- var data = {
- jsonrpc: "2.0",
- method: fct_name,
- params: params,
- id: Math.floor(Math.random() * 1000 * 1000 * 1000)
- };
- var xhr = fct(data);
- var result = xhr.pipe(function(result) {
- core.bus.trigger('rpc:result', data, result);
- if (result.error !== undefined) {
- if (result.error.data.arguments[0] !== "bus.Bus not available in test mode") {
- console.error("Server application error", JSON.stringify(result.error));
- }
- return $.Deferred().reject("server", result.error);
- } else {
- return result.result;
- }
- }, function() {
- //console.error("JsonRPC communication error", _.toArray(arguments));
- var def = $.Deferred();
- return def.reject.apply(def, ["communication"].concat(_.toArray(arguments)));
- });
- // FIXME: jsonp?
- result.abort = function () { if (xhr.abort) xhr.abort(); };
- return result;
-}
-
-function jsonRpc(url, fct_name, params, settings) {
- return genericJsonRpc(fct_name, params, function(data) {
- return $.ajax(url, _.extend({}, settings, {
- url: url,
- dataType: 'json',
- type: 'POST',
- data: JSON.stringify(data, time.date_to_utc),
- contentType: 'application/json'
- }));
- });
-}
-
-function jsonpRpc(url, fct_name, params, settings) {
- settings = settings || {};
- return genericJsonRpc(fct_name, params, function(data) {
- var payload_str = JSON.stringify(data, time.date_to_utc);
- var payload_url = $.param({r:payload_str});
- var force2step = settings.force2step || false;
- delete settings.force2step;
- var session_id = settings.session_id || null;
- delete settings.session_id;
- if (payload_url.length < 2000 && ! force2step) {
- return $.ajax(url, _.extend({}, settings, {
- url: url,
- dataType: 'jsonp',
- jsonp: 'jsonp',
- type: 'GET',
- cache: false,
- data: {r: payload_str, session_id: session_id}
- }));
- } else {
- var args = {session_id: session_id, id: data.id};
- var ifid = _.uniqueId('oe_rpc_iframe');
- var html = "<iframe src='javascript:false;' name='" + ifid + "' id='" + ifid + "' style='display:none'></iframe>";
- var $iframe = $(html);
- var nurl = 'jsonp=1&' + $.param(args);
- nurl = url.indexOf("?") !== -1 ? url + "&" + nurl : url + "?" + nurl;
- var $form = $('<form>')
- .attr('method', 'POST')
- .attr('target', ifid)
- .attr('enctype', "multipart/form-data")
- .attr('action', nurl)
- .append($('<input type="hidden" name="r" />').attr('value', payload_str))
- .hide()
- .appendTo($('body'));
- var cleanUp = function() {
- if ($iframe) {
- $iframe.unbind("load").remove();
- }
- $form.remove();
- };
- var deferred = $.Deferred();
- // the first bind is fired up when the iframe is added to the DOM
- $iframe.bind('load', function() {
- // the second bind is fired up when the result of the form submission is received
- $iframe.unbind('load').bind('load', function() {
- $.ajax({
- url: url,
- dataType: 'jsonp',
- jsonp: 'jsonp',
- type: 'GET',
- cache: false,
- data: {session_id: session_id, id: data.id}
- }).always(function() {
- cleanUp();
- }).done(function() {
- deferred.resolve.apply(deferred, arguments);
- }).fail(function() {
- deferred.reject.apply(deferred, arguments);
- });
- });
- // now that the iframe can receive data, we fill and submit the form
- $form.submit();
- });
- // append the iframe to the DOM (will trigger the first load)
- $form.after($iframe);
- if (settings.timeout) {
- realSetTimeout(function() {
- deferred.reject({});
- }, settings.timeout);
- }
- return deferred;
- }
- });
-}
-
-// helper function to make a rpc with a function name hardcoded to 'call'
-function rpc(url, params, settings) {
- return jsonRpc(url, 'call', params, settings);
-}
-
-// helper
-function realSetTimeout (fct, millis) {
- var finished = new Date().getTime() + millis;
- var wait = function() {
- var current = new Date().getTime();
- if (current < finished) {
- setTimeout(wait, finished - current);
- } else {
- fct();
- }
- };
- setTimeout(wait, millis);
-}
-
-function loadCSS(url) {
- if (!$('link[href="' + url + '"]').length) {
- $('head').append($('<link>', {
- 'href': url,
- 'rel': 'stylesheet',
- 'type': 'text/css'
- }));
- }
-}
-
-var loadJS = (function () {
- var urls = [];
- var defs = [];
-
- var load = function loadJS(url) {
- // Check the DOM to see if a script with the specified url is already there
- var alreadyRequired = ($('script[src="' + url + '"]').length > 0);
-
- // If loadJS was already called with the same URL, it will have a registered deferred indicating if
- // the script has been fully loaded. If not, the deferred has to be initialized. This is initialized
- // as already resolved if the script was already there without the need of loadJS.
- var index = _.indexOf(urls, url);
- if (index < 0) {
- urls.push(url);
- index = defs.push(alreadyRequired ? $.when() : $.Deferred()) - 1;
- }
-
- // Get the script associated deferred and returns it after initializing the script if needed. The
- // deferred is marked to be resolved on script load and rejected on script error.
- var def = defs[index];
- if (!alreadyRequired) {
- var script = document.createElement('script');
- script.type = 'text/javascript';
- script.src = url;
- script.onload = script.onreadystatechange = function() {
- if ((script.readyState && script.readyState !== "loaded" && script.readyState !== "complete") || script.onload_done) {
- return;
- }
- script.onload_done = true;
- def.resolve(url);
- };
- script.onerror = function () {
- console.error("Error loading file", script.src);
- def.reject(url);
- };
- var head = document.head || document.getElementsByTagName('head')[0];
- head.appendChild(script);
- }
- return def;
- };
-
- return load;
-})();
-
-
-/**
- * Cooperative file download implementation, for ajaxy APIs.
- *
- * Requires that the server side implements an httprequest correctly
- * setting the `fileToken` cookie to the value provided as the `token`
- * parameter. The cookie *must* be set on the `/` path and *must not* be
- * `httpOnly`.
- *
- * It would probably also be a good idea for the response to use a
- * `Content-Disposition: attachment` header, especially if the MIME is a
- * "known" type (e.g. text/plain, or for some browsers application/json
- *
- * @param {Object} options
- * @param {String} [options.url] used to dynamically create a form
- * @param {Object} [options.data] data to add to the form submission. If can be used without a form, in which case a form is created from scratch. Otherwise, added to form data
- * @param {HTMLFormElement} [options.form] the form to submit in order to fetch the file
- * @param {Function} [options.success] callback in case of download success
- * @param {Function} [options.error] callback in case of request error, provided with the error body
- * @param {Function} [options.complete] called after both ``success`` and ``error` callbacks have executed
- */
-function get_file(options) {
- // need to detect when the file is done downloading (not used
- // yet, but we'll need it to fix the UI e.g. with a throbber
- // while dump is being generated), iframe load event only fires
- // when the iframe content loads, so we need to go smarter:
- // http://geekswithblogs.net/GruffCode/archive/2010/10/28/detecting-the-file-download-dialog-in-the-browser.aspx
- var timer, token = new Date().getTime(),
- cookie_name = 'fileToken', cookie_length = cookie_name.length,
- CHECK_INTERVAL = 1000, id = _.uniqueId('get_file_frame'),
- remove_form = false;
-
-
- // iOS devices doesn't allow iframe use the way we do it,
- // opening a new window seems the best way to workaround
- if (navigator.userAgent.match(/(iPod|iPhone|iPad)/)) {
- var params = _.extend({}, options.data || {}, {token: token});
- var url = options.session.url(options.url, params);
- if (options.complete) { options.complete(); }
-
- return window.open(url);
- }
-
- var $form, $form_data = $('<div>');
-
- var complete = function () {
- if (options.complete) { options.complete(); }
- clearTimeout(timer);
- $form_data.remove();
- $target.remove();
- if (remove_form && $form) { $form.remove(); }
- };
- var $target = $('<iframe style="display: none;">')
- .attr({id: id, name: id})
- .appendTo(document.body)
- .load(function () {
- try {
- if (options.error) {
- var body = this.contentDocument.body;
- var nodes = body.children.length === 0 ? body.childNodes : body.children;
- var node = nodes[1] || nodes[0];
- options.error(JSON.parse(node.textContent));
- }
- } finally {
- complete();
- }
- });
-
- if (options.form) {
- $form = $(options.form);
- } else {
- remove_form = true;
- $form = $('<form>', {
- action: options.url,
- method: 'POST'
- }).appendTo(document.body);
- }
- if (core.csrf_token) {
- $('<input type="hidden" name="csrf_token">')
- .val(core.csrf_token)
- .appendTo($form_data);
- }
-
- var hparams = _.extend({}, options.data || {}, {token: token});
- _.each(hparams, function (value, key) {
- var $input = $form.find('[name=' + key +']');
- if (!$input.length) {
- $input = $('<input type="hidden" name="' + key + '">')
- .appendTo($form_data);
- }
- $input.val(value);
- });
-
- $form
- .append($form_data)
- .attr('target', id)
- .get(0).submit();
-
- var waitLoop = function () {
- var cookies = document.cookie.split(';');
- // setup next check
- timer = setTimeout(waitLoop, CHECK_INTERVAL);
- for (var i=0; i<cookies.length; ++i) {
- var cookie = cookies[i].replace(/^\s*/, '');
- if (!cookie.indexOf(cookie_name === 0)) { continue; }
- var cookie_val = cookie.substring(cookie_length + 1);
- if (parseInt(cookie_val, 10) !== token) { continue; }
-
- // clear cookie
- document.cookie = _.str.sprintf("%s=;expires=%s;path=/",
- cookie_name, new Date().toGMTString());
- if (options.success) { options.success(); }
- complete();
- return;
- }
- };
- timer = setTimeout(waitLoop, CHECK_INTERVAL);
-};
-
-function post (controller_url, data) {
-
- var progressHandler = function (deferred) {
- return function (state) {
- if(state.lengthComputable) {
- deferred.notify({
- h_loaded: utils.human_size(state.loaded),
- h_total : utils.human_size(state.total),
- loaded : state.loaded,
- total : state.total,
- pcent : Math.round((state.loaded/state.total)*100)
- });
- }
- };
- };
-
- var Def = $.Deferred();
- var postData = new FormData();
-
- $.each(data, function(i,val) {
- postData.append(i, val);
- });
- if (core.csrf_token) {
- postData.append('csrf_token', core.csrf_token);
- }
-
- var xhr = new XMLHttpRequest();
- if(xhr.upload) xhr.upload.addEventListener('progress', progressHandler(Def), false);
-
- var ajaxDef = $.ajax(controller_url, {
- xhr: function() {return xhr;},
- data: postData,
- processData: false,
- contentType: false,
- type: 'POST'
- }).then(function (data) {Def.resolve(data);})
- .fail(function (data) {Def.reject(data);});
-
- return Def;
-}
-
-var loadXML = (function () {
- var loading = false;
- var urls = [];
- var qwebs = [];
- var templates_def = $.Deferred();
-
- var load = function loadXML(url, qweb) {
- if (url) {
- urls.push(url);
- qwebs.push(qweb);
- }
-
- if (!loading && urls.length) {
- if (templates_def.state() === "resolved") {
- templates_def = $.Deferred();
- }
-
- loading = true;
- qwebs.shift().add_template(urls.shift(), function () {
- loading = false;
- if (!urls.length) {
- templates_def.resolve();
- }
- load(null);
- });
- }
-
- return templates_def;
- };
-
- return load;
-})();
-
-return {
- jsonRpc: jsonRpc,
- jsonpRpc: jsonpRpc,
- rpc: rpc,
- loadCSS: loadCSS,
- loadJS: loadJS,
- loadXML: loadXML,
- get_file: get_file,
- post: post,
-};
-
-});