var VnObject = require ('./object'); var JsonException = require ('./json-exception'); /** * Handler for JSON rest connections. */ module.exports = new Class ({ Extends: VnObject ,_connected: false ,_requestsCount: 0 ,token: null /** * Initilizes the connection object. */ ,initialize: function () { this.parent (); this.fetchToken (); } ,fetchToken: function () { var token = null; if (sessionStorage.getItem ('vnToken')) token = sessionStorage.getItem ('vnToken'); if (localStorage.getItem ('vnToken')) token = localStorage.getItem ('vnToken'); this.token = token; } ,clearToken: function () { this.token = null; localStorage.removeItem ('vnToken'); sessionStorage.removeItem ('vnToken'); } /** * Opens the connection to the REST service. * * @param {string} user The user name * @param {string} password The user password * @param {boolean} remember Specifies if the user should be remembered * @param {function} openCallback The function to call when operation is done */ ,open: function (user, pass, remember, callback) { if (user !== null && user !== undefined) { var params = { user: user, password: pass, remember: remember }; } else var params = null; this.send ('core/login', params, this._onOpen.bind (this, callback, remember)); } /* * Called when open operation is done. */ ,_onOpen: function (callback, remember, json, error) { if (json && json.login) { this._connected = true; this.token = json.token; var storage = remember ? localStorage : sessionStorage; storage.setItem ('vnToken', this.token); this.emit ('openned'); } else this._closeClient (); if (callback) callback (this, this._connected, error); } /** * Closes the connection to the REST service. * * @param {function} callback The function to call when operation is done */ ,close: function (callback) { this._closeClient (); this.send ('core/logout', null, this._onClose.bind (this, callback)); } /* * Called when close operation is done. */ ,_onClose: function (callback, json, error) { this.emit ('closed'); if (callback) callback (this, json === true, error); } ,_closeClient: function () { this._connected = false; this.clearToken (); } /** * Suppants another user. * * @param {string} user The user name * @param {function} callback The callback function */ ,supplantUser: function (user, callback) { var params = {'supplantUser': user}; this.send ('core/supplant', params, this._onUserSupplant.bind (this, callback)); } ,_onUserSupplant: function (callback, json) { if (json) this.token = json; if (callback) callback (json != null); } /** * Ends the user supplanting and restores the last login. */ ,supplantEnd: function () { this.fetchToken (); } /** * Executes the specified REST service with the given params and calls * the callback when response is received. * * @param {string} restService The service path * @param {Map} params The params to pass to the service * @param {function} callback The response callback */ ,send: function (restService, params, callback) { if (!params) params = {}; params['srv'] = 'json:'+ restService; this.sendWithUrl (params, callback, 'POST', '.'); } ,sendForm: function (form, callback) { var params = {}; var elements = form.elements; for (var i = 0; i < elements.length; i++) if (elements[i].name) params[elements[i].name] = elements[i].value; this.sendWithUrl (params, callback, 'POST', form.action); } ,sendFormMultipart: function (form, callback) { var formData = new FormData (form); if (this.token) formData.append ('token', this.token); var request = new XMLHttpRequest (); request.open ('POST', form.action, true); request.onreadystatechange = this._onStateChange.bind (this, request, callback); request.send (formData); this._addRequest (); } ,sendFormData: function (formData, callback) { if (this.token) formData.append ('token', this.token); var request = new XMLHttpRequest (); request.open ('post', '', true); request.onreadystatechange = this._onStateChange.bind (this, request, callback); request.send (formData); this._addRequest (); } /* * Called when REST response is received. */ ,sendWithUrl: function (params, callback, method, url) { if (this.token) params['token'] = this.token; var request = new XMLHttpRequest (); request.open (method, url, true); request.setRequestHeader ('Content-Type', 'application/x-www-form-urlencoded'); request.onreadystatechange = this._onStateChange.bind (this, request, callback); request.send (Vn.Url.makeUri (params)); this._addRequest (); } ,_addRequest: function () { this._requestsCount++; if (this._requestsCount === 1) this.emit ('loading-changed', true); } ,_onStateChange: function (request, callback) { if (request.readyState !== 4) return; this._requestsCount--; if (this._requestsCount === 0) this.emit ('loading-changed', false); var data = null; var error = null; try { if (request.status == 0) { var ex = new JsonException (); ex.message = _('The server does not respond, please check your Internet connection'); throw ex; } var contentType = null; try { contentType = request .getResponseHeader ('Content-Type') .split (';')[0] .trim (); } catch (e) {} if (contentType != 'application/json') { var ex = new JsonException (); ex.message = request.statusText; ex.code = request.status; throw ex; } var json = JSON.parse (request.responseText); var jsData = json.data; //var jsWarns = json.warnings; if (request.status == 200) { data = jsData; } else { var exception = jsData.exception; if (exception) exception = exception .replace (/\\/g, '.') .replace (/Exception$/, '') .replace (/^Vn\.Web\./, ''); var ex = new JsonException (); Object.assign (ex, { exception: exception, message: jsData.message, code: jsData.code, file: jsData.file, line: jsData.line, trace: jsData.trace }); throw ex; } } catch (e) { data = null; error = e; } if (callback) // try { callback (data, error); /* error = null; } catch (e) { error = e; } */ if (error) { if (error.exception == 'SessionExpired') this.clearToken (); this.emit ('error', error); } } });