/** * * /$$ * | $$ * | $$ /$$ /$$ /$$$$$$$ /$$$$$$ /$$$$$$ * | $$ | $$ | $$| $$__ $$ /$$__ $$ /$$__ $$ * | $$ | $$ | $$| $$ \ $$| $$ \ $$| $$ \ $$ * | $$ | $$ | $$| $$ | $$| $$ | $$| $$ | $$ * | $$$$$$$$| $$$$$$/| $$ | $$| $$$$$$$| $$$$$$/ * |________/ \______/ |__/ |__/ \____ $$ \______/ * /$$ \ $$ * | $$$$$$/ * \______/ * * @copyright 2011-2012 TapQuo Inc (c) * @license http://www.github.com/tapquo/lungo/blob/master/LICENSE.txt * @version 1.2 * @link https://github.com/TapQuo/Lungo.js * * @author Javier Jimenez Villar || @soyjavi * @author Guillermo Pascual || @pasku1 */ var LUNGO = LUNGO || {}; LUNGO.VERSION = '1.2'; LUNGO.Attributes || (LUNGO.Attributes = {}); LUNGO.Data || (LUNGO.Data = {}); LUNGO.Sugar || (LUNGO.Sugar = {}); LUNGO.View || (LUNGO.View = {}); LUNGO.Device || (LUNGO.Device = {}); LUNGO.ready || (LUNGO.ready = Quo().ready); /** * Object with data-attributes (HTML5) with a special * * @namespace LUNGO * @class Constants * * @author Javier Jimenez Villar || @soyjavi * @author Guillermo Pascual || @pasku1 */ LUNGO.Constants = { ELEMENT: { SECTION: 'section', ARTICLE: 'article', ASIDE: 'aside', BODY: 'body', DIV: 'div', LIST: '
    ', SPAN: ' ' }, CLASS: { ACTIVE: 'active', ASIDE: 'aside', SHOW: 'show', SHOW_REVOKE: 'show-revoke', HIDE: 'hide', HIDE_REVOKE: 'hide-revoke', CURRENT: 'current', RIGHT: 'onright', LEFT: 'onleft', HORIZONTAL: 'horizontal', FLOW: 'flow' }, TRIGGER: { LOAD: 'load', UNLOAD: 'unload' }, ATTRIBUTE: { ID: 'id', HREF: 'href', TITLE: 'title', ARTICLE: 'article', CLASS: 'class', WIDTH: 'width', HEIGHT: 'height', PIXEL: 'px', PERCENT: '%', TARGET: 'target', FIRST: 'first', LAST: 'last', EMPTY: '' }, BINDING: { START: '{{', END: '}}', KEY: 'value', PARSER: /\{{.*?\}}/gi }, ERROR: { CREATE_SCROLL: 'ERROR: Impossible to create a without ID.', BINDING_DATA_TYPE: 'ERROR: Processing the type of binding data.', BINDING_TEMPLATE: 'ERROR: Binding Template not exists >> ', BINDING_LIST: 'ERROR: Processing parameters for list binding.', DATABASE: 'ERROR: Connecting to Data.Sql.', ROUTER: 'ERROR: The target does not exists >>', LOADING_RESOURCE: 'ERROR: Loading resource.' } }; /** * Lungo sandbox APP initialization * * @namespace LUNGO * @class App * * @author Javier Jimenez Villar || @soyjavi * @author Guillermo Pascual || @pasku1 */ LUNGO.App = (function(lng, undefined) { var default_config = { id: 1, name: 'lungo_app', version: 1.0, icon: '' }; /** * Initializes all LungoJS system: setting properties for the application, * subscribing to automatic events, initializing sections & articles * and stating the title. * * @method init * * @param {object} Application configuration properties */ var init = function(app_config) { default_config = lng.Core.mix(default_config, app_config); lng.Boot(); }; var get = function(property) { return default_config[property]; }; return { init: init, get: get }; })(LUNGO); /** * Contains all the common functions used in Lungo. * * @namespace LUNGO * @class Core * * @author Javier Jimenez Villar || @soyjavi * @author Guillermo Pascual || @pasku1 */ LUNGO.Core = (function(lng, $$, undefined) { var ARRAY_PROTO = Array.prototype; var HASHTAG_CHARACTER = '#'; /** * Console system to display messages when you are in debug mode. * * @method log * * @param {number} Severity based in (1)Log, (2)Warn, (>2)Error * @param {string} Message to show in console */ var log = function(severity, message) { if (!lng.Core.isMobile()) { console[(severity === 1) ? 'log' : (severity === 2) ? 'warn' : 'error'](message); } else { // @todo : send to the server } }; /** * Executes callbacks based on the parameters received. * * @method execute * * @param {Function} callback to execute */ var execute = function() { var args = toArray(arguments); var callback = args.shift(); if (toType(callback) === 'function') { callback.apply(null, args); } }; /** * Creates a new function that, when called, itself calls this function in * the context of the provided this value, with a given sequence of arguments * preceding any provided when the new function was called. * * @method bind * * @param {object} object to which the 'this' can refer in the new function when the new function is called. * @param {Function} method A function object. */ var bind = function(object, method) { return function() { return method.apply(object, toArray(arguments)); }; }; /** * Copy from any number of objects and mix them all into a new object. * The implementation is simple; just loop through arguments and * copy every property of every object passed to the function. * * @method mix * * @param {object} arguments to mix them all into a new object. * @return {object} child a new object with all the objects from the arguments mixed. */ var mix = function() { var child = child || {}; for (var arg = 0, len = arguments.length; arg < len; arg++) { var argument = arguments[arg]; for (var prop in argument) { if (isOwnProperty(argument, prop)) { child[prop] = argument[prop]; } } } return child; }; /** * Every object descended from Object inherits the hasOwnProperty method. * This method can be used to determine whether an object has the specified property * as a direct property of that object. * * @param {object} object to test for a property's existence inside itself. * @param {string} property the name of the property to test. * @return {boolean} indicating whether the object has the specified property. */ var isOwnProperty = function(object, property) { return $$.isOwnProperty(object, property); }; /** * Determine the internal JavaScript [[Class]] of an object. * * @param {object} obj to get the real type of itself. * @return {string} with the internal JavaScript [[Class]] of itself. */ var toType = function(obj) { return $$.toType(obj); }; /** * Convert an array-like object into a true JavaScript array. * * @param {object} obj Any object to turn into a native Array. * @return {object} The object is now a plain array. */ var toArray = function(obj) { return ARRAY_PROTO.slice.call(obj, 0); }; /** * Determine if the current environment is a mobile environment * * @method isMobile * * @return {boolean} true if is mobile environment, false if not. */ var isMobile = function() { return $$.isMobile(); }; /** * Returns information of execute environment * * @method environment * * @return {object} Environment information */ var environment = function() { return $$.environment(); }; /** * Returns a ordered list of objects by a property * * @method orderByProperty * * @param {list} List of objects * @param {string} Name of property * @param {string} Type of order: asc (ascendent) or desc (descendent) * @return {list} Ordered list */ var orderByProperty = function(data, property, order) { var order_operator = (order === 'desc') ? -1 : 1; return data.sort(function(a, b) { return (a[property] < b[property]) ? - order_operator : (a[property] > b[property]) ? order_operator : 0; } ); }; /** * Returns a correct URL using hashtag character * * @method parseUrl * * @param {string} Url * @return {string} Url parsed */ var parseUrl = function(href) { var href_hashtag = href.lastIndexOf(HASHTAG_CHARACTER); if (href_hashtag > 0) { href = href.substring(href_hashtag); } else if (href_hashtag === -1) { href = HASHTAG_CHARACTER + href ; } return href; }; /** * Returns a Object in a list by a property value * * @method objectInListByProperty * * @param {list} List of objects * @param {string} Name of property * @param {var} Value for comparision * @return {object} Instance of object founded (if exists) */ var findByProperty = function(list, property, value) { var search = null; for (var i = 0, len = list.length; i < len; i++) { var element = list[i]; if (element[property] == value) { search = element; break; } }; return search; }; return { log: log, execute: execute, bind: bind, mix: mix, isOwnProperty: isOwnProperty, toType: toType, toArray: toArray, isMobile: isMobile, environment: environment, orderByProperty: orderByProperty, parseUrl: parseUrl, findByProperty: findByProperty }; })(LUNGO, Quo); /** * LungoJS Dom Handler * * @namespace LUNGO * @class Dom * * @author Javier Jimenez Villar || @soyjavi * @author Guillermo Pascual || @pasku1 */ /** * Add an event listener * * @method dom * * @param {string} element selector * @return {Object} QuoJS instance */ LUNGO.dom = function(selector) { return $$(selector); }; /** * External Data & Services Manager * * @namespace LUNGO * @class Service * @requires QuoJS * * @author Javier Jimenez Villar || @soyjavi * @author Guillermo Pascual || @pasku1 */ LUNGO.Service = (function(lng, $$, undefined) { var URL_CACHE_INDEX_KEY = 'lungojs_service_cache'; var DATE_PATTERN = { MINUTE: 'minute', HOUR: 'hour', DAY: 'day' }; /** * Load data from the server using a HTTP GET request. * * @method get * * @param {string} Containing the URL to which the request is sent * @param {object} A map or string that is sent to the server with the request * @param {Function} Callback function after the request [OPTIONAL] * @param {string} Mime-Type: json, xml, html, or text [OPTIONAL] */ var get = function(url, data, success, dataType) { return $$.get(url, data, success, dataType); }; /** * Load data from the server using a HTTP POST request. * * @method post * * @param {string} Containing the URL to which the request is sent * @param {object} A map or string that is sent to the server with the request * @param {Function} Callback function after the request [OPTIONAL] * @param {string} Mime-Type: json, xml, html, or text [OPTIONAL] */ var post = function(url, data, success, dataType) { return $$.post(url, data, success, dataType); }; /** * Load data from the server using a HTTP GET request. * * @method json * * @param {string} Containing the URL to which the request is sent * @param {object} A map or string that is sent to the server with the request * @param {Function} [OPTIONAL] Callback function after the request */ var json = function(url, data, success) { return $$.json(url, data, success); }; /** * Auto-caching system with date pattern. * * @method cache * * @param {string} Containing the URL to which the request is sent * @param {object} A map or string that is sent to the server with the request * @param {string} Date pattern (example: 15 minutes, 1 hour, 3 days) * @param {Function} [OPTIONAL] Callback function after the request * @param {string} Mime-Type: json, xml, html, or text [OPTIONAL] */ var cache = function(url, data, date_pattern, callback, dataType) { var url_key = url + $$.serializeParameters(data); if (_urlCached(url_key, date_pattern)) { var value = lng.Data.Storage.persistent(url_key); if (value) { return callback.call(callback, value); } } else { return $$.get(url, data, function(result) { _saveServiceInCache(url_key, result); callback.call(callback, result); }, dataType); } }; var _urlCached = function(url, date_pattern) { var in_cache = false; var url_cache_index = lng.Data.Storage.persistent(URL_CACHE_INDEX_KEY); if (url_cache_index) { var time_between = _calculateTimeSpent(url_cache_index[url]); in_cache = _checkIsValidPattern(time_between, date_pattern); } return in_cache; }; var _calculateTimeSpent = function(url_last_access) { var now = new Date().getTime(); var service_last_access = new Date(url_last_access).getTime(); return now - service_last_access; }; var _checkIsValidPattern = function(time_between, date_pattern) { var pattern = date_pattern.split(' '); var diference_time = _calculateDiferenceTime(pattern[1], time_between); return (diference_time < pattern[0]) ? true : false; }; var _calculateDiferenceTime = function(pattern_name, time_between) { var diference = (time_between / 1000) / 60; if (pattern_name.indexOf(DATE_PATTERN.HOUR) >= 0) { diference = diference / 60; } else if (pattern_name.indexOf(DATE_PATTERN.DAY) >= 0) { diference = (diference / 60) / 24; } return diference; }; var _saveServiceInCache = function(url, result) { var service_cache_index = lng.Data.Storage.persistent(URL_CACHE_INDEX_KEY) || {}; service_cache_index[url] = new Date(); lng.Data.Storage.persistent(URL_CACHE_INDEX_KEY, service_cache_index); lng.Data.Storage.persistent(url, result); }; return { get: get, post: post, json: json, cache: cache, Settings: $$.ajaxSettings }; })(LUNGO, Quo); /** * ? * * @namespace LUNGO * @class Fallback * * @author Javier Jimenez Villar || @soyjavi */ LUNGO.Fallback = (function(lng, undefined) { var CLASS = lng.Constants.CLASS; var androidButtons = function() { environment = lng.Core.environment(); if (environment.isMobile && environment.os.name === 'android') { lng.dom(document.body).on('touchstart', '.button', _addClassActiveToButton); lng.dom(document.body).on('touchend', '.button', _removeClassActiveToButton); } }; var androidInputs = function(article_id, active) { environment = lng.Core.environment(); if (environment.isMobile && environment.os.name === 'android' && environment.os.version < '4') { var selector = article_id + ' input, ' + article_id + ' textarea, ' + article_id + ' select'; var input_elements = lng.dom(selector); for (var i = 0, len = input_elements.length; i < len; i++) { (active) ? _enableAndroidInput(input_elements[i]) : _disableAndroidInput(input_elements[i]); } } }; var positionFixed = function(sections) { environment = lng.Core.environment(); if (environment.isMobile && environment.os.name === 'ios' && environment.os.version >= '4.2') { sections.style('position', 'fixed'); } }; var _enableAndroidInput = function(input) { input.removeAttribute('disabled'); }; var _disableAndroidInput = function(input) { input.setAttribute('disabled', 'disabled'); }; var _addClassActiveToButton = function(element) { lng.dom(this).addClass(CLASS.ACTIVE); }; var _removeClassActiveToButton = function(element) { lng.dom(this).removeClass(CLASS.ACTIVE); }; return { androidButtons: androidButtons, androidInputs: androidInputs, positionFixed: positionFixed } })(LUNGO); /** * Handles the and to show * * @namespace LUNGO * @class Router * * @author Javier Jimenez Villar || @soyjavi * @author Guillermo Pascual || @pasku1 */ LUNGO.Router = (function(lng, undefined) { var CLASS = lng.Constants.CLASS; var ELEMENT = lng.Constants.ELEMENT; var ERROR = lng.Constants.ERROR; var TRIGGER = lng.Constants.TRIGGER; /** * Navigate to a
    . * * @method section * * @param {string} Id of the
    */ var section = function(section_id) { var section_id = lng.Core.parseUrl(section_id); var current = _getHistoryCurrent(); var target = ELEMENT.SECTION + section_id; if (_existsTarget(target)) { lng.dom(current).removeClass(CLASS.HIDE_REVOKE).removeClass(CLASS.SHOW).addClass(CLASS.HIDE); lng.dom(target).removeClass(CLASS.SHOW_REVOKE).addClass(CLASS.SHOW).trigger(TRIGGER.LOAD); lng.Router.History.add(section_id); } }; /** * Displays the
    in a particular
    . * * @method article * * @param {string}
    Id * @param {string}
    Id */ var article = function(section_id, article_id) { var section_id = lng.Core.parseUrl(section_id); var article_id = lng.Core.parseUrl(article_id); var target = ELEMENT.SECTION + section_id + ' ' + ELEMENT.ARTICLE + article_id; if (_existsTarget(target)) { lng.dom(target).trigger(TRIGGER.LOAD); lng.View.Article.show(section_id, article_id); } }; /** * Displays the