/* Jappix - An open social platform These are the common JS script for Jappix ------------------------------------------------- License: dual-licensed under AGPL and MPLv2 Authors: Valérian Saliou, olivierm, regilero, Maranda */ // Bundle var Common = (function () { /** * Alias of this * @private */ var self = {}; /* Constants */ self.R_DOMAIN_NAME = /^(([a-zA-Z0-9-\.]+)\.)?[a-zA-Z0-9][a-zA-Z0-9-]{1,61}[a-zA-Z0-9]\.[a-zA-Z]{2,}$/i; /** * Checks if an element exists in the DOM * @public * @param {string} path * @return {boolean} */ self.exists = function(path) { var exists = false; try { if(jQuery(path).size() > 0) { exists = true; } } catch(e) { Console.error('Common.exists', e); } finally { return exists; } }; /** * Checks if Jappix is connected * @public * @return {boolean} */ self.isConnected = function() { connected = false; try { if((typeof con != 'undefined') && con && con.connected()) { connected = true; } } catch(e) { Console.error('Common.isConnected', e); } finally { return connected; } }; /** * Checks if Jappix is connected * @public * @return {boolean} */ self.hasWebSocket = function() { has_websocket = false; try { if(HOST_WEBSOCKET && typeof window.WebSocket != 'undefined') { has_websocket = true; } } catch(e) { Console.error('Common.hasWebSocket', e); } finally { return has_websocket; } }; /** * Checks if Jappix has focus * @public * @return {boolean} */ self.isFocused = function() { has_focus = true; try { if(!document.hasFocus()) { has_focus = false; } } catch(e) { Console.error('Common.isFocused', e); } finally { return has_focus; } }; /** * Matches a domain name * @public * @param {string} xid * @return {boolean} */ self.isDomain = function(xid) { is_domain = false; try { if(xid.match(self.R_DOMAIN_NAME)) { is_domain = true; } } catch(e) { Console.error('Common.isDomain', e); } finally { return is_domain; } }; /** * Generates the good XID * @public * @param {string} xid * @param {string} type * @return {string} */ self.generateXID = function(xid, type) { try { // XID needs to be transformed xid = xid.toLowerCase(); if(xid && (xid.indexOf('@') === -1)) { // Groupchat XID if(type == 'groupchat') { return xid + '@' + HOST_MUC; } // Gateway XID if(self.isDomain(xid) === true) { return xid; } // User XID return xid + '@' + HOST_MAIN; } // Nothing special (yet bare XID) return xid; } catch(e) { Console.error('Common.generateXID', e); } }; /** * Gets the asked translated string * @public * @param {string} string * @return {string} */ self._e = function(string) { try { return string; } catch(e) { Console.error('Common._e', e); } }; /** * Replaces '%s' to a given value for a translated string * @public * @param {string} string * @param {string} value * @return {string} */ self.printf = function(string, value) { try { return string.replace('%s', value); } catch(e) { Console.error('Common.printf', e); } }; /** * Returns the string after the last given char * @public * @param {string} given_char * @param {string} str * @return {string} */ self.strAfterLast = function(given_char, str) { try { if(!given_char || !str) { return ''; } var char_index = str.lastIndexOf(given_char); var str_return = str; if(char_index >= 0) { str_return = str.substr(char_index + 1); } return str_return; } catch(e) { Console.error('Common.strAfterLast', e); } }; /** * Properly explodes a string with a given character * @public * @param {string} toEx * @param {string} toStr * @param {number} i * @return {string} */ self.explodeThis = function(toEx, toStr, i) { try { // Get the index of our char to explode var index = toStr.indexOf(toEx); // We split if necessary the string if(index !== -1) { if(i === 0) { toStr = toStr.substr(0, index); } else { toStr = toStr.substr(index + 1); } } // We return the value return toStr; } catch(e) { Console.error('Common.explodeThis', e); } }; /** * Cuts the resource of a XID * @public * @param {string} aXID * @return {string} */ self.cutResource = function(aXID) { try { return self.explodeThis('/', aXID, 0); } catch(e) { Console.error('Common.cutResource', e); } }; /** * Gets the resource of a XID * @public * @param {string} aXID * @return {string} */ self.thisResource = function(aXID) { resource = ''; try { // Any resource? if(self.isFullXID(aXID)) { resource = self.explodeThis('/', aXID, 1); } } catch(e) { Console.error('Common.thisResource', e); } finally { return resource; } }; /** * Returns whether this XID is full or not * @public * @param {string} xid * @return {boolean} */ self.isFullXID = function(xid) { try { return xid.indexOf('/') !== -1; } catch(e) { Console.error('Common.isFullXID', e); return false; } }; /** * nodepreps an XMPP node * @public * @param {string} node * @return {string} */ self.nodeprep = function(node) { // Spec: http://tools.ietf.org/html/rfc6122#appendix-A try { if(!node) { return node; } // Remove prohibited chars var prohibited_chars = ['"', '&', '\'', '/', ':', '<', '>', '@']; for(var j in prohibited_chars) { node = node.replace(prohibited_chars[j], ''); } // Lower case node = node.toLowerCase(); return node; } catch(e) { Console.error('Common.nodeprep', e); } }; /** * Encodes quotes in a string * @public * @param {string} str * @return {string} */ self.encodeQuotes = function(str) { try { return (str + '').htmlEnc(); } catch(e) { Console.error('Common.encodeQuotes', e); } }; /** * Escapes quotes in a string * @public * @param {string} str * @return {string} */ self.escapeQuotes = function(str) { try { return escape(self.encodeQuotes(str)); } catch(e) { Console.error('Common.escapeQuotes', e); } }; /** * Unescapes quotes in a string * @public * @param {string} str * @return {string} */ self.unescapeQuotes = function(str) { try { return unescape(str); } catch(e) { Console.error('Common.unescapeQuotes', e); } }; /** * Gets the bare XID from a XID * @public * @param {string} xid * @return {string} */ self.bareXID = function(xid) { try { // Cut the resource xid = self.cutResource(xid); // Launch nodeprep if(xid.indexOf('@') !== -1) { xid = self.nodeprep(self.getXIDNick(xid, true)) + '@' + self.getXIDHost(xid); } return xid; } catch(e) { Console.error('Common.bareXID', e); } }; /** * Gets the full XID from a XID * @public * @param {string} xid * @return {string} */ self.fullXID = function(xid) { try { // Normalizes the XID var full = self.bareXID(xid); var resource = self.thisResource(xid); // Any resource? if(resource) { full += '/' + resource; } return full; } catch(e) { Console.error('Common.fullXID', e); } }; /** * Gets the nick from a XID * @public * @param {string} aXID * @param {boolean} raw_explode * @return {string} */ self.getXIDNick = function(aXID, raw_explode) { try { if(raw_explode !== true) { // Gateway nick? if(aXID.match(/\\40/)) { return self.explodeThis('\\40', aXID, 0); } } return self.explodeThis('@', aXID, 0); } catch(e) { Console.error('Common.getXIDNick', e); } }; /** * Gets the host from a XID * @public * @param {string} aXID * @return {string} */ self.getXIDHost = function(aXID) { try { return self.explodeThis('@', aXID, 1); } catch(e) { Console.error('Common.getXIDHost', e); } }; /** * Checks if we are RTL (Right-To-Left) * @public * @return {boolean} */ self.isRTL = function() { try { return (self._e("default:LTR") == 'default:RTL'); } catch(e) { Console.error('Common.isRTL', e); } }; /** * Checks if anonymous mode is allowed * @public * @return {boolean} */ self.allowedAnonymous = function() { try { return (ANONYMOUS == 'on'); } catch(e) { Console.error('Common.allowedAnonymous', e); } }; /** * Checks if host is locked * @public * @return {boolean} */ self.lockHost = function() { try { return (LOCK_HOST == 'on'); } catch(e) { Console.error('Common.lockHost', e); } }; /** * Gets the bare XID of the user * @public * @return {string} */ self.getXID = function() { try { // Return the XID of the user if(con.username && con.domain) { return con.username + '@' + con.domain; } return ''; } catch(e) { Console.error('Common.getXID', e); } }; /** * Gets the full XID of the user * @public * @return {string} */ self.getFullXID = function() { try { var xid = self.getXID(); // Return the full XID of the user if(xid) { return xid + '/' + con.resource; } return ''; } catch(e) { Console.error('Common.getFullXID', e); } }; /** * Generates the colors for a given user XID * @public * @param {type} xid * @return {string} */ self.generateColor = function(xid) { try { var colors = new Array( 'ac0000', 'a66200', '007703', '00705f', '00236b', '4e005c' ); var number = 0; for(var i = 0; i < xid.length; i++) { number += xid.charCodeAt(i); } var color = '#' + colors[number % (colors.length)]; return color; } catch(e) { Console.error('Common.generateColor', e); } }; /** * Checks if the XID is a gateway * @public * @param {string} xid * @return {boolean} */ self.isGateway = function(xid) { is_gateway = true; try { if(xid.indexOf('@') !== -1) { is_gateway = false; } } catch(e) { Console.error('Common.isGateway', e); } finally { return is_gateway; } }; /** * Gets the from attribute of a stanza (overrides some servers like Prosody missing from attributes) * @public * @param {object} stanza * @return {string} */ self.getStanzaFrom = function(stanza) { try { var from = stanza.getFrom(); // No from, we assume this is our XID if(!from) { from = self.getXID(); } return from; } catch(e) { Console.error('Common.getStanzaFrom', e); } }; /** * Returns whether the stanza has been really sent from our own server or entity * @public * @param {object} stanza * @return {string} */ self.isSafeStanza = function(stanza) { var is_safe = false; try { var from = self.getStanzaFrom(stanza); is_safe = (!from || from == con.domain || from == self.getXID()) && true; } catch(e) { Console.error('Common.isSafeStanza', e); } finally { return is_safe; } }; /** * Adds a zero to a date when needed * @public * @param {number} i * @return {string} */ self.padZero = function(i) { try { // Negative number (without first 0) if(i > -10 && i < 0) { return '-0' + (i * -1); } // Positive number (without first 0) if(i < 10 && i >= 0) { return '0' + i; } // All is okay return i; } catch(e) { Console.error('Common.padZero', e); } }; /** * Escapes a string (or an array of string) for a regex usage. In case of an * array, escapes are not done "in place", keeping the query unmodified * @public * @param {object} query * @return {object} */ self.escapeRegex = function(query) { var result = []; try { if(query instanceof Array) { result = [query.length]; for(i = 0; i < query.length; i++) { try { result[i] = Common.escapeRegex(query[i]); } catch(e) { Console.error('Common.escapeRegex', e); result[i] = null; } } } else { try { result = query.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&'); } catch(e) { Console.error('Common.escapeRegex[inner]', e); } } } catch(e) { Console.error('Common.escapeRegex', e); } finally { return result; } }; /** * Returns a random array value * @public * @param {object} arr * @return {object} */ self.randomArrayValue = function(arr) { try { return arr[Math.floor(Math.random() * arr.length)]; } catch(e) { Console.error('Common.randomArrayValue', e); } }; /** * Returns whether the browser is mobile or not * @public * @return {boolean} */ self.isMobile = function() { is_mobile = false; try { is_mobile = /Android|iPhone|iPod|iPad|Windows Phone|BlackBerry|Bada|Maemo|Meego|webOS/i.test(navigator.userAgent); } catch(e) { Console.error('Common.isMobile', e); } finally { return is_mobile; } }; /** * Converts a XML document to a string * @public * @param {object} xmlData * @return {string} */ self.xmlToString = function(xmlData) { xml_str = null; try { // For Mozilla, Firefox, Opera, etc. if(window.XMLSerializer) { xml_str = (new XMLSerializer()).serializeToString(xmlData); } // For Internet Explorer if(window.ActiveXObject) { xml_str = xmlData.xml; } } catch(e) { Console.error('Common.xmlToString', e); } finally { return xml_str; } }; /** * Converts a string to a XML document * @public * @param {string} sXML * @return {object} */ self.XMLFromString = function(sXML) { try { // No data? if(!sXML) { return ''; } // Add the XML tag if(!sXML.match(/^<\?xml/i)) { sXML = '' + sXML; } // Parse it! if(window.DOMParser) { return (new DOMParser()).parseFromString(sXML, 'text/xml'); } if(window.ActiveXObject) { var oXML = new ActiveXObject('Microsoft.XMLDOM'); oXML.loadXML(sXML); return oXML; } } catch(e) { Console.error('Common.XMLFromString', e); return ''; } }; /** * Watches for input value change (delays callback) * @public * @param {function} cb * @return {function} */ self.typewatch = function(cb) { try { var timer = 0; return function(callback, ms) { clearTimeout(timer); timer = setTimeout(callback, ms); }; } catch(e) { Console.error('Common.typewatch', e); } }; /** * Return class scope */ return self; })(); var JappixCommon = Common;