lungo-1.2.js 67 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524
  1. /**
  2. *
  3. * /$$
  4. * | $$
  5. * | $$ /$$ /$$ /$$$$$$$ /$$$$$$ /$$$$$$
  6. * | $$ | $$ | $$| $$__ $$ /$$__ $$ /$$__ $$
  7. * | $$ | $$ | $$| $$ \ $$| $$ \ $$| $$ \ $$
  8. * | $$ | $$ | $$| $$ | $$| $$ | $$| $$ | $$
  9. * | $$$$$$$$| $$$$$$/| $$ | $$| $$$$$$$| $$$$$$/
  10. * |________/ \______/ |__/ |__/ \____ $$ \______/
  11. * /$$ \ $$
  12. * | $$$$$$/
  13. * \______/
  14. *
  15. * @copyright 2011-2012 TapQuo Inc (c)
  16. * @license http://www.github.com/tapquo/lungo/blob/master/LICENSE.txt
  17. * @version 1.2
  18. * @link https://github.com/TapQuo/Lungo.js
  19. *
  20. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  21. * @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
  22. */
  23. var LUNGO = LUNGO || {};
  24. LUNGO.VERSION = '1.2';
  25. LUNGO.Attributes || (LUNGO.Attributes = {});
  26. LUNGO.Data || (LUNGO.Data = {});
  27. LUNGO.Sugar || (LUNGO.Sugar = {});
  28. LUNGO.View || (LUNGO.View = {});
  29. LUNGO.Device || (LUNGO.Device = {});
  30. LUNGO.ready || (LUNGO.ready = Quo().ready);
  31. /**
  32. * Object with data-attributes (HTML5) with a special <markup>
  33. *
  34. * @namespace LUNGO
  35. * @class Constants
  36. *
  37. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  38. * @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
  39. */
  40. LUNGO.Constants = {
  41. ELEMENT: {
  42. SECTION: 'section',
  43. ARTICLE: 'article',
  44. ASIDE: 'aside',
  45. BODY: 'body',
  46. DIV: 'div',
  47. LIST: '<ul></ul>',
  48. SPAN: '<span>&nbsp;</span>'
  49. },
  50. CLASS: {
  51. ACTIVE: 'active',
  52. ASIDE: 'aside',
  53. SHOW: 'show',
  54. SHOW_REVOKE: 'show-revoke',
  55. HIDE: 'hide',
  56. HIDE_REVOKE: 'hide-revoke',
  57. CURRENT: 'current',
  58. RIGHT: 'onright',
  59. LEFT: 'onleft',
  60. HORIZONTAL: 'horizontal',
  61. FLOW: 'flow'
  62. },
  63. TRIGGER: {
  64. LOAD: 'load',
  65. UNLOAD: 'unload'
  66. },
  67. ATTRIBUTE: {
  68. ID: 'id',
  69. HREF: 'href',
  70. TITLE: 'title',
  71. ARTICLE: 'article',
  72. CLASS: 'class',
  73. WIDTH: 'width',
  74. HEIGHT: 'height',
  75. PIXEL: 'px',
  76. PERCENT: '%',
  77. TARGET: 'target',
  78. FIRST: 'first',
  79. LAST: 'last',
  80. EMPTY: ''
  81. },
  82. BINDING: {
  83. START: '{{',
  84. END: '}}',
  85. KEY: 'value',
  86. PARSER: /\{{.*?\}}/gi
  87. },
  88. ERROR: {
  89. CREATE_SCROLL: 'ERROR: Impossible to create a <scroll> without ID.',
  90. BINDING_DATA_TYPE: 'ERROR: Processing the type of binding data.',
  91. BINDING_TEMPLATE: 'ERROR: Binding Template not exists >> ',
  92. BINDING_LIST: 'ERROR: Processing parameters for list binding.',
  93. DATABASE: 'ERROR: Connecting to Data.Sql.',
  94. ROUTER: 'ERROR: The target does not exists >>',
  95. LOADING_RESOURCE: 'ERROR: Loading resource.'
  96. }
  97. };
  98. /**
  99. * Lungo sandbox APP initialization
  100. *
  101. * @namespace LUNGO
  102. * @class App
  103. *
  104. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  105. * @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
  106. */
  107. LUNGO.App = (function(lng, undefined) {
  108. var default_config = {
  109. id: 1,
  110. name: 'lungo_app',
  111. version: 1.0,
  112. icon: ''
  113. };
  114. /**
  115. * Initializes all LungoJS system: setting properties for the application,
  116. * subscribing to automatic events, initializing sections & articles
  117. * and stating the title.
  118. *
  119. * @method init
  120. *
  121. * @param {object} Application configuration properties
  122. */
  123. var init = function(app_config) {
  124. default_config = lng.Core.mix(default_config, app_config);
  125. lng.Boot();
  126. };
  127. var get = function(property) {
  128. return default_config[property];
  129. };
  130. return {
  131. init: init,
  132. get: get
  133. };
  134. })(LUNGO);
  135. /**
  136. * Contains all the common functions used in Lungo.
  137. *
  138. * @namespace LUNGO
  139. * @class Core
  140. *
  141. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  142. * @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
  143. */
  144. LUNGO.Core = (function(lng, $$, undefined) {
  145. var ARRAY_PROTO = Array.prototype;
  146. var HASHTAG_CHARACTER = '#';
  147. /**
  148. * Console system to display messages when you are in debug mode.
  149. *
  150. * @method log
  151. *
  152. * @param {number} Severity based in (1)Log, (2)Warn, (>2)Error
  153. * @param {string} Message to show in console
  154. */
  155. var log = function(severity, message) {
  156. if (!lng.Core.isMobile()) {
  157. console[(severity === 1) ? 'log' : (severity === 2) ? 'warn' : 'error'](message);
  158. } else {
  159. // @todo : send to the server
  160. }
  161. };
  162. /**
  163. * Executes callbacks based on the parameters received.
  164. *
  165. * @method execute
  166. *
  167. * @param {Function} callback to execute
  168. */
  169. var execute = function() {
  170. var args = toArray(arguments);
  171. var callback = args.shift();
  172. if (toType(callback) === 'function') {
  173. callback.apply(null, args);
  174. }
  175. };
  176. /**
  177. * Creates a new function that, when called, itself calls this function in
  178. * the context of the provided this value, with a given sequence of arguments
  179. * preceding any provided when the new function was called.
  180. *
  181. * @method bind
  182. *
  183. * @param {object} object to which the 'this' can refer in the new function when the new function is called.
  184. * @param {Function} method A function object.
  185. */
  186. var bind = function(object, method) {
  187. return function() {
  188. return method.apply(object, toArray(arguments));
  189. };
  190. };
  191. /**
  192. * Copy from any number of objects and mix them all into a new object.
  193. * The implementation is simple; just loop through arguments and
  194. * copy every property of every object passed to the function.
  195. *
  196. * @method mix
  197. *
  198. * @param {object} arguments to mix them all into a new object.
  199. * @return {object} child a new object with all the objects from the arguments mixed.
  200. */
  201. var mix = function() {
  202. var child = child || {};
  203. for (var arg = 0, len = arguments.length; arg < len; arg++) {
  204. var argument = arguments[arg];
  205. for (var prop in argument) {
  206. if (isOwnProperty(argument, prop)) {
  207. child[prop] = argument[prop];
  208. }
  209. }
  210. }
  211. return child;
  212. };
  213. /**
  214. * Every object descended from Object inherits the hasOwnProperty method.
  215. * This method can be used to determine whether an object has the specified property
  216. * as a direct property of that object.
  217. *
  218. * @param {object} object to test for a property's existence inside itself.
  219. * @param {string} property the name of the property to test.
  220. * @return {boolean} indicating whether the object has the specified property.
  221. */
  222. var isOwnProperty = function(object, property) {
  223. return $$.isOwnProperty(object, property);
  224. };
  225. /**
  226. * Determine the internal JavaScript [[Class]] of an object.
  227. *
  228. * @param {object} obj to get the real type of itself.
  229. * @return {string} with the internal JavaScript [[Class]] of itself.
  230. */
  231. var toType = function(obj) {
  232. return $$.toType(obj);
  233. };
  234. /**
  235. * Convert an array-like object into a true JavaScript array.
  236. *
  237. * @param {object} obj Any object to turn into a native Array.
  238. * @return {object} The object is now a plain array.
  239. */
  240. var toArray = function(obj) {
  241. return ARRAY_PROTO.slice.call(obj, 0);
  242. };
  243. /**
  244. * Determine if the current environment is a mobile environment
  245. *
  246. * @method isMobile
  247. *
  248. * @return {boolean} true if is mobile environment, false if not.
  249. */
  250. var isMobile = function() {
  251. return $$.isMobile();
  252. };
  253. /**
  254. * Returns information of execute environment
  255. *
  256. * @method environment
  257. *
  258. * @return {object} Environment information
  259. */
  260. var environment = function() {
  261. return $$.environment();
  262. };
  263. /**
  264. * Returns a ordered list of objects by a property
  265. *
  266. * @method orderByProperty
  267. *
  268. * @param {list} List of objects
  269. * @param {string} Name of property
  270. * @param {string} Type of order: asc (ascendent) or desc (descendent)
  271. * @return {list} Ordered list
  272. */
  273. var orderByProperty = function(data, property, order) {
  274. var order_operator = (order === 'desc') ? -1 : 1;
  275. return data.sort(function(a, b) {
  276. return (a[property] < b[property]) ? - order_operator :
  277. (a[property] > b[property])
  278. ?
  279. order_operator : 0;
  280. }
  281. );
  282. };
  283. /**
  284. * Returns a correct URL using hashtag character
  285. *
  286. * @method parseUrl
  287. *
  288. * @param {string} Url
  289. * @return {string} Url parsed
  290. */
  291. var parseUrl = function(href) {
  292. var href_hashtag = href.lastIndexOf(HASHTAG_CHARACTER);
  293. if (href_hashtag > 0) {
  294. href = href.substring(href_hashtag);
  295. } else if (href_hashtag === -1) {
  296. href = HASHTAG_CHARACTER + href ;
  297. }
  298. return href;
  299. };
  300. /**
  301. * Returns a Object in a list by a property value
  302. *
  303. * @method objectInListByProperty
  304. *
  305. * @param {list} List of objects
  306. * @param {string} Name of property
  307. * @param {var} Value for comparision
  308. * @return {object} Instance of object founded (if exists)
  309. */
  310. var findByProperty = function(list, property, value) {
  311. var search = null;
  312. for (var i = 0, len = list.length; i < len; i++) {
  313. var element = list[i];
  314. if (element[property] == value) {
  315. search = element;
  316. break;
  317. }
  318. };
  319. return search;
  320. };
  321. return {
  322. log: log,
  323. execute: execute,
  324. bind: bind,
  325. mix: mix,
  326. isOwnProperty: isOwnProperty,
  327. toType: toType,
  328. toArray: toArray,
  329. isMobile: isMobile,
  330. environment: environment,
  331. orderByProperty: orderByProperty,
  332. parseUrl: parseUrl,
  333. findByProperty: findByProperty
  334. };
  335. })(LUNGO, Quo);
  336. /**
  337. * LungoJS Dom Handler
  338. *
  339. * @namespace LUNGO
  340. * @class Dom
  341. *
  342. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  343. * @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
  344. */
  345. /**
  346. * Add an event listener
  347. *
  348. * @method dom
  349. *
  350. * @param {string} <Markup> element selector
  351. * @return {Object} QuoJS <element> instance
  352. */
  353. LUNGO.dom = function(selector) {
  354. return $$(selector);
  355. };
  356. /**
  357. * External Data & Services Manager
  358. *
  359. * @namespace LUNGO
  360. * @class Service
  361. * @requires QuoJS
  362. *
  363. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  364. * @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
  365. */
  366. LUNGO.Service = (function(lng, $$, undefined) {
  367. var URL_CACHE_INDEX_KEY = 'lungojs_service_cache';
  368. var DATE_PATTERN = {
  369. MINUTE: 'minute',
  370. HOUR: 'hour',
  371. DAY: 'day'
  372. };
  373. /**
  374. * Load data from the server using a HTTP GET request.
  375. *
  376. * @method get
  377. *
  378. * @param {string} Containing the URL to which the request is sent
  379. * @param {object} A map or string that is sent to the server with the request
  380. * @param {Function} Callback function after the request [OPTIONAL]
  381. * @param {string} Mime-Type: json, xml, html, or text [OPTIONAL]
  382. */
  383. var get = function(url, data, success, dataType) {
  384. return $$.get(url, data, success, dataType);
  385. };
  386. /**
  387. * Load data from the server using a HTTP POST request.
  388. *
  389. * @method post
  390. *
  391. * @param {string} Containing the URL to which the request is sent
  392. * @param {object} A map or string that is sent to the server with the request
  393. * @param {Function} Callback function after the request [OPTIONAL]
  394. * @param {string} Mime-Type: json, xml, html, or text [OPTIONAL]
  395. */
  396. var post = function(url, data, success, dataType) {
  397. return $$.post(url, data, success, dataType);
  398. };
  399. /**
  400. * Load data from the server using a HTTP GET request.
  401. *
  402. * @method json
  403. *
  404. * @param {string} Containing the URL to which the request is sent
  405. * @param {object} A map or string that is sent to the server with the request
  406. * @param {Function} [OPTIONAL] Callback function after the request
  407. */
  408. var json = function(url, data, success) {
  409. return $$.json(url, data, success);
  410. };
  411. /**
  412. * Auto-caching system with date pattern.
  413. *
  414. * @method cache
  415. *
  416. * @param {string} Containing the URL to which the request is sent
  417. * @param {object} A map or string that is sent to the server with the request
  418. * @param {string} Date pattern (example: 15 minutes, 1 hour, 3 days)
  419. * @param {Function} [OPTIONAL] Callback function after the request
  420. * @param {string} Mime-Type: json, xml, html, or text [OPTIONAL]
  421. */
  422. var cache = function(url, data, date_pattern, callback, dataType) {
  423. var url_key = url + $$.serializeParameters(data);
  424. if (_urlCached(url_key, date_pattern)) {
  425. var value = lng.Data.Storage.persistent(url_key);
  426. if (value) {
  427. return callback.call(callback, value);
  428. }
  429. } else {
  430. return $$.get(url, data, function(result) {
  431. _saveServiceInCache(url_key, result);
  432. callback.call(callback, result);
  433. }, dataType);
  434. }
  435. };
  436. var _urlCached = function(url, date_pattern) {
  437. var in_cache = false;
  438. var url_cache_index = lng.Data.Storage.persistent(URL_CACHE_INDEX_KEY);
  439. if (url_cache_index) {
  440. var time_between = _calculateTimeSpent(url_cache_index[url]);
  441. in_cache = _checkIsValidPattern(time_between, date_pattern);
  442. }
  443. return in_cache;
  444. };
  445. var _calculateTimeSpent = function(url_last_access) {
  446. var now = new Date().getTime();
  447. var service_last_access = new Date(url_last_access).getTime();
  448. return now - service_last_access;
  449. };
  450. var _checkIsValidPattern = function(time_between, date_pattern) {
  451. var pattern = date_pattern.split(' ');
  452. var diference_time = _calculateDiferenceTime(pattern[1], time_between);
  453. return (diference_time < pattern[0]) ? true : false;
  454. };
  455. var _calculateDiferenceTime = function(pattern_name, time_between) {
  456. var diference = (time_between / 1000) / 60;
  457. if (pattern_name.indexOf(DATE_PATTERN.HOUR) >= 0) {
  458. diference = diference / 60;
  459. } else if (pattern_name.indexOf(DATE_PATTERN.DAY) >= 0) {
  460. diference = (diference / 60) / 24;
  461. }
  462. return diference;
  463. };
  464. var _saveServiceInCache = function(url, result) {
  465. var service_cache_index = lng.Data.Storage.persistent(URL_CACHE_INDEX_KEY) || {};
  466. service_cache_index[url] = new Date();
  467. lng.Data.Storage.persistent(URL_CACHE_INDEX_KEY, service_cache_index);
  468. lng.Data.Storage.persistent(url, result);
  469. };
  470. return {
  471. get: get,
  472. post: post,
  473. json: json,
  474. cache: cache,
  475. Settings: $$.ajaxSettings
  476. };
  477. })(LUNGO, Quo);
  478. /**
  479. * ?
  480. *
  481. * @namespace LUNGO
  482. * @class Fallback
  483. *
  484. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  485. */
  486. LUNGO.Fallback = (function(lng, undefined) {
  487. var CLASS = lng.Constants.CLASS;
  488. var androidButtons = function() {
  489. environment = lng.Core.environment();
  490. if (environment.isMobile && environment.os.name === 'android') {
  491. lng.dom(document.body).on('touchstart', '.button', _addClassActiveToButton);
  492. lng.dom(document.body).on('touchend', '.button', _removeClassActiveToButton);
  493. }
  494. };
  495. var androidInputs = function(article_id, active) {
  496. environment = lng.Core.environment();
  497. if (environment.isMobile && environment.os.name === 'android' && environment.os.version < '4') {
  498. var selector = article_id + ' input, ' + article_id + ' textarea, ' + article_id + ' select';
  499. var input_elements = lng.dom(selector);
  500. for (var i = 0, len = input_elements.length; i < len; i++) {
  501. (active) ? _enableAndroidInput(input_elements[i]) : _disableAndroidInput(input_elements[i]);
  502. }
  503. }
  504. };
  505. var positionFixed = function(sections) {
  506. environment = lng.Core.environment();
  507. if (environment.isMobile && environment.os.name === 'ios' && environment.os.version >= '4.2') {
  508. sections.style('position', 'fixed');
  509. }
  510. };
  511. var _enableAndroidInput = function(input) {
  512. input.removeAttribute('disabled');
  513. };
  514. var _disableAndroidInput = function(input) {
  515. input.setAttribute('disabled', 'disabled');
  516. };
  517. var _addClassActiveToButton = function(element) {
  518. lng.dom(this).addClass(CLASS.ACTIVE);
  519. };
  520. var _removeClassActiveToButton = function(element) {
  521. lng.dom(this).removeClass(CLASS.ACTIVE);
  522. };
  523. return {
  524. androidButtons: androidButtons,
  525. androidInputs: androidInputs,
  526. positionFixed: positionFixed
  527. }
  528. })(LUNGO);
  529. /**
  530. * Handles the <sections> and <articles> to show
  531. *
  532. * @namespace LUNGO
  533. * @class Router
  534. *
  535. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  536. * @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
  537. */
  538. LUNGO.Router = (function(lng, undefined) {
  539. var CLASS = lng.Constants.CLASS;
  540. var ELEMENT = lng.Constants.ELEMENT;
  541. var ERROR = lng.Constants.ERROR;
  542. var TRIGGER = lng.Constants.TRIGGER;
  543. /**
  544. * Navigate to a <section>.
  545. *
  546. * @method section
  547. *
  548. * @param {string} Id of the <section>
  549. */
  550. var section = function(section_id) {
  551. var section_id = lng.Core.parseUrl(section_id);
  552. var current = _getHistoryCurrent();
  553. var target = ELEMENT.SECTION + section_id;
  554. if (_existsTarget(target)) {
  555. lng.dom(current).removeClass(CLASS.HIDE_REVOKE).removeClass(CLASS.SHOW).addClass(CLASS.HIDE);
  556. lng.dom(target).removeClass(CLASS.SHOW_REVOKE).addClass(CLASS.SHOW).trigger(TRIGGER.LOAD);
  557. lng.Router.History.add(section_id);
  558. }
  559. };
  560. /**
  561. * Displays the <article> in a particular <section>.
  562. *
  563. * @method article
  564. *
  565. * @param {string} <section> Id
  566. * @param {string} <article> Id
  567. */
  568. var article = function(section_id, article_id) {
  569. var section_id = lng.Core.parseUrl(section_id);
  570. var article_id = lng.Core.parseUrl(article_id);
  571. var target = ELEMENT.SECTION + section_id + ' ' + ELEMENT.ARTICLE + article_id;
  572. if (_existsTarget(target)) {
  573. lng.dom(target).trigger(TRIGGER.LOAD);
  574. lng.View.Article.show(section_id, article_id);
  575. }
  576. };
  577. /**
  578. * Displays the <aside> in a particular <section>.
  579. *
  580. * @method aside
  581. *
  582. * @param {string} <section> Id
  583. * @param {string} <aside> Id
  584. */
  585. var aside = function(section_id, aside_id) {
  586. var section_id = lng.Core.parseUrl(section_id);
  587. var aside_id = lng.Core.parseUrl(aside_id);
  588. var target = ELEMENT.ASIDE + aside_id;
  589. if (_existsTarget(target)) {
  590. var is_visible = lng.dom(target).hasClass(CLASS.CURRENT);
  591. if (is_visible) {
  592. lng.View.Aside.hide(section_id, aside_id);
  593. } else {
  594. lng.View.Aside.show(section_id, aside_id);
  595. }
  596. }
  597. };
  598. /**
  599. * Return to previous section.
  600. *
  601. * @method back
  602. */
  603. var back = function() {
  604. var current_section = ELEMENT.SECTION + _getHistoryCurrent();
  605. lng.dom(current_section).removeClass(CLASS.SHOW).addClass(CLASS.SHOW_REVOKE).trigger(TRIGGER.UNLOAD);
  606. lng.Router.History.removeLast();
  607. lng.dom(_getHistoryCurrent()).removeClass(CLASS.HIDE).addClass(CLASS.HIDE_REVOKE).addClass(CLASS.SHOW);
  608. };
  609. var _existsTarget = function(target) {
  610. var exists = false;
  611. if (lng.dom(target).length > 0) {
  612. exists = true;
  613. } else {
  614. lng.Core.log(3, ERROR.ROUTER + target);
  615. }
  616. return exists;
  617. };
  618. var _getHistoryCurrent = function() {
  619. return lng.Router.History.current();
  620. };
  621. return {
  622. section: section,
  623. article: article,
  624. aside: aside,
  625. back: back
  626. };
  627. })(LUNGO);
  628. /**
  629. * Stores the displayed <sections> as a historical.
  630. *
  631. * @namespace LUNGO.Router
  632. * @class History
  633. *
  634. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  635. * @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
  636. */
  637. LUNGO.Router.History = (function(undefined) {
  638. var _history = [];
  639. /**
  640. * Create a new element to the browsing history based on the current section id.
  641. *
  642. * @method add
  643. *
  644. * @param {string} Id of the section
  645. */
  646. var add = function(section_id) {
  647. if (section_id !== current()) {
  648. _history.push(section_id);
  649. }
  650. };
  651. /**
  652. * Returns the current browsing history section id.
  653. *
  654. * @method current
  655. *
  656. * @return {string} Current section id
  657. */
  658. var current = function() {
  659. return _history[_history.length - 1];
  660. };
  661. /**
  662. * Removes the current item browsing history.
  663. *
  664. * @method removeLast
  665. */
  666. var removeLast = function() {
  667. _history.length -= 1;
  668. };
  669. return {
  670. add: add,
  671. current: current,
  672. removeLast: removeLast
  673. };
  674. })();
  675. /**
  676. * Initialize the <articles> layout of a certain <section>
  677. *
  678. * @namespace LUNGO.View
  679. * @class Article
  680. *
  681. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  682. * @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
  683. */
  684. LUNGO.View.Article = (function(lng, undefined) {
  685. var ELEMENT = lng.Constants.ELEMENT;
  686. var CLASS = lng.Constants.CLASS;
  687. var ATTRIBUTE = lng.Constants.ATTRIBUTE;
  688. var TRIGGER = lng.Constants.TRIGGER;
  689. var SELECTORS = {
  690. NAVIGATION_ITEM: 'a[href][data-target="article"]',
  691. REFERENCE_LINK: ' a[href][data-article]'
  692. };
  693. /**
  694. * ?
  695. *
  696. * @method show
  697. */
  698. var show = function(section_id, article_id) {
  699. _toggleNavItems(section_id, article_id);
  700. showReferenceLinks(section_id, article_id.replace('#', ''));
  701. _showContainer(section_id, article_id);
  702. };
  703. /**
  704. * ?
  705. *
  706. * @method showReferenceLinks
  707. */
  708. var showReferenceLinks = function(section_id, article_id) {
  709. var links = lng.dom(ELEMENT.SECTION + section_id + SELECTORS.REFERENCE_LINK);
  710. for (var i = 0, len = links.length; i < len; i++) {
  711. var link = lng.dom(links[i]);
  712. (link.data(ATTRIBUTE.ARTICLE) === article_id) ? link.show() : link.hide();
  713. }
  714. };
  715. var _toggleNavItems = function(section_id, article_id) {
  716. var nav_items = lng.dom(section_id + ' ' + SELECTORS.NAVIGATION_ITEM);
  717. nav_items.removeClass(CLASS.CURRENT);
  718. for (var i = 0, len = nav_items.length; i < len; i++) {
  719. var nav_item = lng.dom(nav_items[i]);
  720. var nav_item_parsed_url = lng.Core.parseUrl(nav_item.attr(ATTRIBUTE.HREF));
  721. if (nav_item_parsed_url === article_id) {
  722. nav_item.addClass(CLASS.CURRENT);
  723. _setTitle(section_id, nav_item);
  724. }
  725. }
  726. };
  727. var _showContainer = function(section_id, article_id) {
  728. var section_articles = section_id + ' ' + ELEMENT.ARTICLE + '.' + CLASS.CURRENT;
  729. var current_active_article_id = '#' + lng.dom(section_articles).attr(ATTRIBUTE.ID);
  730. lng.dom(section_articles).removeClass(CLASS.CURRENT).trigger(TRIGGER.UNLOAD);
  731. lng.Fallback.androidInputs(current_active_article_id, false);
  732. lng.dom(article_id).addClass(CLASS.CURRENT);
  733. lng.Fallback.androidInputs(article_id, true);
  734. };
  735. var _setTitle = function(id, item) {
  736. var title = item.data(ATTRIBUTE.TITLE);
  737. if (title) {
  738. var section_title = id + ' header .title, ' + id + ' footer .title';
  739. lng.dom(section_title).text(title);
  740. }
  741. };
  742. return {
  743. show: show,
  744. showReferenceLinks: showReferenceLinks
  745. };
  746. })(LUNGO);
  747. /**
  748. *
  749. *
  750. * @namespace LUNGO.View
  751. * @class Resize
  752. *
  753. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  754. * @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
  755. */
  756. LUNGO.View.Resize = (function(lng, undefined) {
  757. var ATTRIBUTE = lng.Constants.ATTRIBUTE;
  758. /**
  759. * Sets toolbars width, using total screen width
  760. *
  761. * @method toolbars
  762. */
  763. var toolbars = function() {
  764. var toolbar = '.toolbar nav, .groupbar';
  765. var all_toolbars = lng.dom(toolbar);
  766. for (var i = 0, len = all_toolbars.length; i < len; i++) {
  767. var toolbar = lng.dom(all_toolbars[i]);
  768. var toolbar_children = toolbar.children();
  769. var toolbar_children_percent = 100 / toolbar.children().length;
  770. toolbar_children.style(ATTRIBUTE.WIDTH, toolbar_children_percent + ATTRIBUTE.PERCENT);
  771. }
  772. };
  773. return {
  774. toolbars: toolbars
  775. };
  776. })(LUNGO);
  777. /**
  778. * Lungo Template system
  779. *
  780. * @namespace LUNGO.View
  781. * @class Template
  782. *
  783. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  784. * @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
  785. */
  786. LUNGO.View.Template = (function(lng, undefined) {
  787. var ERROR = lng.Constants.ERROR;
  788. var _templates = {};
  789. /**
  790. * Create a new databinding template based on a <markup>
  791. *
  792. * @method create
  793. *
  794. * @param {String} Id of the new databinding template
  795. * @param {String} <markup> of the new databinding template
  796. */
  797. var create = function(id, markup) {
  798. _templates[id] = markup;
  799. };
  800. /**
  801. * Returns the existence of a certain Id databinding template
  802. *
  803. * @method exists
  804. *
  805. * @param {String} Id of the databinding template
  806. * @return {Boolean} true if exists, false if not.
  807. */
  808. var exists = function(id) {
  809. return (_templates[id]) ? true : false;
  810. };
  811. /**
  812. * Returns the instance of a certain Id databinding template
  813. *
  814. * @method get
  815. *
  816. * @param {String} Id of the databinding template
  817. * @return {String} Markup of template
  818. */
  819. var get = function(id) {
  820. return _templates[id];
  821. };
  822. /**
  823. * Performs databinding process for a data set and a given template
  824. *
  825. * @method render
  826. *
  827. * @param {String} Element selector for showing the result of databinding
  828. * @param {String} Databinding Template Id
  829. * @param {Object} Data for binding
  830. * @param {Function} Callback when the process is complete
  831. */
  832. var render = function(element, template_id, data, callback) {
  833. if (lng.View.Template.exists(template_id)) {
  834. var container = lng.dom(element);
  835. var markup = this.markup(template_id, data);
  836. container.html(markup);
  837. lng.Core.execute(callback);
  838. } else {
  839. lng.Core.log(3, ERROR.BINDING_TEMPLATE + template_id);
  840. }
  841. };
  842. /**
  843. * Performs databinding process for a data set and a given template
  844. *
  845. * @method markup
  846. *
  847. * @param {String} Databinding Template Id
  848. * @param {Object} Data for binding
  849. */
  850. var markup = function(template_id, data) {
  851. return lng.View.Template.Binding.create(template_id, data);
  852. };
  853. return {
  854. create: create,
  855. exists: exists,
  856. get: get,
  857. render: render,
  858. markup: markup
  859. };
  860. })(LUNGO);
  861. /**
  862. * Lungo Data-Binding system
  863. *
  864. * @namespace LUNGO.View.Template
  865. * @class Binding
  866. *
  867. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  868. * @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
  869. */
  870. LUNGO.View.Template.Binding = (function(lng, undefined) {
  871. var BINDING = lng.Constants.BINDING;
  872. var ERROR = lng.Constants.ERROR;
  873. /**
  874. * Performs databinding process for a data set and a given template
  875. *
  876. * @method create
  877. *
  878. * @param {String} Databinding Template Id
  879. * @param {Object} Data for binding
  880. */
  881. var create = function(template_id, data) {
  882. var template = lng.View.Template.get(template_id);
  883. return _processData(data, template);
  884. };
  885. var dataAttribute = function(element, attribute) {
  886. var data = element.data(attribute.tag);
  887. if (data) {
  888. var html_binded = attribute.html.replace(BINDING.START + BINDING.KEY + BINDING.END, data);
  889. element.prepend(html_binded);
  890. }
  891. };
  892. var _processData = function(data, template) {
  893. var data_type = lng.Core.toType(data);
  894. if (data_type === 'array') {
  895. return _bindPropertiesInMultiplesElements(data, template);
  896. } else if (data_type === 'object') {
  897. return _bindProperties(data, template);
  898. } else {
  899. lng.Core.log(3, ERROR.BINDING_DATA_TYPE);
  900. }
  901. };
  902. var _bindPropertiesInMultiplesElements = function(elements, template) {
  903. var markup = '';
  904. for (var i = 0, len = elements.length; i < len; i++) {
  905. markup += _bindProperties(elements[i], template);
  906. }
  907. return markup;
  908. };
  909. var _bindProperties = function(element, template) {
  910. var binding_field;
  911. for (var property in element) {
  912. if (lng.Core.isOwnProperty(element, property) && element[property] !== null) {
  913. binding_field = new RegExp(BINDING.START + property + BINDING.END, 'g');
  914. template = template.replace(binding_field, element[property]);
  915. }
  916. }
  917. return _removeNoBindedProperties(template);
  918. };
  919. var _removeNoBindedProperties = function(template) {
  920. return template.replace(BINDING.PARSER, '');
  921. };
  922. return {
  923. create: create,
  924. dataAttribute: dataAttribute
  925. };
  926. })(LUNGO);
  927. /**
  928. * Auto generate lists based on Template and Data-Binding system
  929. *
  930. * @namespace LUNGO.View.Template
  931. * @class List
  932. *
  933. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  934. * @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
  935. */
  936. LUNGO.View.Template.List = (function(lng, undefined) {
  937. var ERROR = lng.Constants.ERROR;
  938. var ATTRIBUTE = lng.Constants.ATTRIBUTE;
  939. /**
  940. * Create a list based DataBind with a configuration object for an element <article>
  941. * if the config has a 'norecords' property it will display the norecords markup rather than nothing.
  942. *
  943. * @method create
  944. *
  945. * @param {object} Id of the container showing the result of databinding
  946. */
  947. var create = function(config) {
  948. config.container = _getContainer(config.el);
  949. if (_validateConfig(config)) {
  950. config.data = _order(config);
  951. _render(config);
  952. _scroll(config.el);
  953. }
  954. };
  955. /**
  956. * Append a list based DataBind with a configuration object for an element <article>
  957. * if the config has a 'norecords' property it will display the norecords markup rather than nothing.
  958. *
  959. * @method append
  960. *
  961. * @param {object} Id of the container showing the result of databinding
  962. */
  963. var append = function(config) {
  964. var markup = lng.View.Template.markup(config.template, config.data);
  965. var container = _getContainer(config.el);
  966. container.append(markup);
  967. _scroll(config.el, ATTRIBUTE.LAST);
  968. };
  969. /**
  970. * Prepend a list based DataBind with a configuration object for an element <article>
  971. * if the config has a 'norecords' property it will display the norecords markup rather than nothing.
  972. *
  973. * @method prepend
  974. *
  975. * @param {object} Id of the container showing the result of databinding
  976. */
  977. var prepend = function(config) {
  978. var markup = lng.View.Template.markup(config.template, config.data);
  979. var container = _getContainer(config.el);
  980. container.prepend(markup);
  981. _scroll(config.el, ATTRIBUTE.FIRST);
  982. };
  983. var _validateConfig = function(config) {
  984. var checked = false;
  985. var container_exists = !! config.container.length > 0;
  986. var template_exists = lng.View.Template.exists(config.template);
  987. if (container_exists && template_exists) {
  988. var type = lng.Core.toType(config.data);
  989. if (type === 'array' || type === 'object') {
  990. checked = true;
  991. }
  992. } else {
  993. lng.Core.log(3, ERROR.BINDING_LIST);
  994. }
  995. return checked;
  996. };
  997. var _getContainer = function(element) {
  998. return lng.dom(element).children().first();
  999. }
  1000. var _order = function(config) {
  1001. if (config.order && config.order.field && config.order.type) {
  1002. config.data = lng.Core.orderByProperty(config.data, config.order.field, config.order.type);
  1003. }
  1004. return config.data;
  1005. };
  1006. var _render = function(config) {
  1007. lng.View.Template.render(config.container.selector, config.template, config.data);
  1008. };
  1009. var _scroll = function(element, direction) {
  1010. var element_id = lng.dom(element).attr(ATTRIBUTE.ID);
  1011. lng.View.Scroll.init(element_id);
  1012. if (direction) {
  1013. lng.View.Scroll[(direction === ATTRIBUTE.FIRST) ? ATTRIBUTE.FIRST : ATTRIBUTE.LAST](element_id);
  1014. }
  1015. };
  1016. return {
  1017. create: create,
  1018. append: append,
  1019. prepend: prepend
  1020. };
  1021. })(LUNGO);
  1022. /**
  1023. * Wrapper of the third library iScroll
  1024. *
  1025. * @namespace LUNGO.View
  1026. * @class Scroll
  1027. * @requires iScroll
  1028. *
  1029. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  1030. * @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
  1031. */
  1032. LUNGO.View.Scroll = (function(lng, undefined) {
  1033. var CLASS = lng.Constants.CLASS;
  1034. var ATTRIBUTE = lng.Constants.ATTRIBUTE;
  1035. var ERROR = lng.Constants.ERROR;
  1036. var DEFAULT_PROPERTIES = {
  1037. hScroll: false,
  1038. vScroll: false,
  1039. useTransition: true,
  1040. momentum: true,
  1041. lockDirection: true,
  1042. fixedScrollbar: true,
  1043. fadeScrollbar: true,
  1044. hideScrollbar: true
  1045. };
  1046. var CACHE_KEY = 'scrolls';
  1047. var SCROLL_TIMEFRAME = 250;
  1048. /**
  1049. * Creates a new iScroll element.
  1050. *
  1051. * @method init
  1052. *
  1053. * @param {string} Id of the container scroll.
  1054. * @param {object} [OPTIONAL] Properties
  1055. */
  1056. var init = function(id, properties) {
  1057. if (id) {
  1058. _render(id, properties);
  1059. } else {
  1060. lng.Core.log(3, ERROR.CREATE_SCROLL);
  1061. }
  1062. };
  1063. /**
  1064. * Update iScroll element with new <markup> content.
  1065. *
  1066. * @method html
  1067. *
  1068. * @param {string} Id of the container scroll.
  1069. * @param {string} Markup content
  1070. */
  1071. var html = function(id, content) {
  1072. var container = _getContainer(id);
  1073. container.html(content);
  1074. _render(id);
  1075. };
  1076. /**
  1077. * Add <markup> content to iScroll instance
  1078. *
  1079. * @method append
  1080. *
  1081. * @param {string} Id of the container scroll.
  1082. * @param {string} Markup content
  1083. */
  1084. var append = function(id, content) {
  1085. var container = _getContainer(id);
  1086. container.append(content);
  1087. _render(id);
  1088. };
  1089. /**
  1090. * Refresh iScroll instance.
  1091. *
  1092. * @method refresh
  1093. *
  1094. * @param {string} Id of the container scroll.
  1095. * @param {object} [OPTIONAL] Properties
  1096. */
  1097. var refresh = function(id, properties) {
  1098. _render(id, properties);
  1099. };
  1100. /**
  1101. * Removes iScroll instance.
  1102. *
  1103. * @method remove
  1104. *
  1105. * @param {string} Id of the container scroll.
  1106. */
  1107. var remove = function(id) {
  1108. if (lng.Data.Cache.exists(CACHE_KEY) && lng.Data.Cache.get(CACHE_KEY, id)) {
  1109. lng.Data.Cache.get(CACHE_KEY, id).destroy();
  1110. lng.Data.Cache.remove(CACHE_KEY, id);
  1111. }
  1112. };
  1113. /**
  1114. * Scrolls the wrapper contents to the minimum x/y coordinates
  1115. *
  1116. * @method first
  1117. *
  1118. * @param {string} Id of the <section>
  1119. */
  1120. var first = function(id) {
  1121. var scroll = lng.Data.Cache.get(CACHE_KEY);
  1122. if (scroll[id]) {
  1123. scroll[id].scrollTo(0, 0, SCROLL_TIMEFRAME);
  1124. }
  1125. };
  1126. /**
  1127. * Scrolls the wrapper contents to the maximum x/y coordinate
  1128. *
  1129. * @method down
  1130. *
  1131. * @param {string} Id of the <section>
  1132. */
  1133. var last = function(id) {
  1134. var scroll = lng.Data.Cache.get(CACHE_KEY, id);
  1135. if (scroll) {
  1136. var element = lng.dom('#' + id).first();
  1137. var content_width = 0;
  1138. var content_height = 0;
  1139. if (_isHorizontal(element)) {
  1140. content_width = -(_sizeProperty(element, ATTRIBUTE.WIDTH));
  1141. } else {
  1142. content_height = -(_sizeProperty(element, ATTRIBUTE.HEIGHT));
  1143. }
  1144. scroll.scrollTo(content_width, content_height, SCROLL_TIMEFRAME);
  1145. }
  1146. };
  1147. var _getContainer = function(id) {
  1148. var scroll = lng.dom('#' + id);
  1149. var container = scroll.children().first();
  1150. if (container.length === 0) {
  1151. scroll.html('<div></div>');
  1152. container = scroll.children().first();
  1153. }
  1154. return container;
  1155. };
  1156. var _sizeProperty = function(element, property) {
  1157. var element_content = element.children().first();
  1158. return element_content[property]() - element[property]();
  1159. };
  1160. var _render = function(id, properties) {
  1161. var scroll = lng.dom('#' + id);
  1162. if (_needScroll(scroll, properties)) {
  1163. properties = _mixProperties(scroll, properties);
  1164. _saveScrollInCache(id, properties);
  1165. } else {
  1166. remove(id);
  1167. }
  1168. };
  1169. var _needScroll = function(scroll, properties) {
  1170. var element = scroll[0];
  1171. var is_horizontal = _isHorizontal(lng.dom(element));
  1172. if (is_horizontal) {
  1173. return (element.clientWidth < element.scrollWidth);
  1174. } else {
  1175. return (element.clientHeight < element.scrollHeight);
  1176. }
  1177. };
  1178. var _saveScrollInCache = function(id, properties) {
  1179. _createScrollIndexInCache();
  1180. var scroll = lng.Data.Cache.get(CACHE_KEY);
  1181. if (!scroll[id]) {
  1182. scroll[id] = new iScroll(id, properties);
  1183. } else {
  1184. scroll[id].refresh();
  1185. }
  1186. lng.Data.Cache.set(CACHE_KEY, scroll);
  1187. };
  1188. var _createScrollIndexInCache = function() {
  1189. if (!lng.Data.Cache.exists(CACHE_KEY)) {
  1190. lng.Data.Cache.set(CACHE_KEY, {});
  1191. }
  1192. };
  1193. var _mixProperties = function(scroll, properties) {
  1194. var scroll_type = _isHorizontal(scroll) ? 'hScroll' : 'vScroll';
  1195. properties || (properties = {});
  1196. properties[scroll_type] = true;
  1197. properties = lng.Core.mix(DEFAULT_PROPERTIES, properties);
  1198. return properties;
  1199. };
  1200. var _isHorizontal = function(scroll) {
  1201. return ( scroll.hasClass(CLASS.HORIZONTAL)) ? true : false;
  1202. };
  1203. return {
  1204. init: init,
  1205. remove: remove,
  1206. refresh: refresh,
  1207. html: html,
  1208. append: append,
  1209. first: first,
  1210. last: last
  1211. };
  1212. })(LUNGO);
  1213. /**
  1214. * Initialize the <articles> layout of a certain <section>
  1215. *
  1216. * @namespace LUNGO.View
  1217. * @class Aside
  1218. *
  1219. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  1220. * @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
  1221. */
  1222. LUNGO.View.Aside = (function(lng, undefined) {
  1223. var ELEMENT = lng.Constants.ELEMENT;
  1224. var CLASS = lng.Constants.CLASS;
  1225. var ATTRIBUTE = lng.Constants.ATTRIBUTE;
  1226. /**
  1227. * Display an aside element for a particular <section>
  1228. *
  1229. * @method show
  1230. *
  1231. * @param {string} Section id
  1232. * @param {string} Aside id
  1233. */
  1234. var show = function(section_id, aside_id) {
  1235. var aside = lng.dom(ELEMENT.ASIDE + aside_id);
  1236. var aside_class = _classFromAside(aside);
  1237. var section = lng.dom(ELEMENT.SECTION + section_id);
  1238. section.addClass(aside_class).addClass(CLASS.ASIDE);
  1239. aside.addClass(CLASS.CURRENT);
  1240. };
  1241. /**
  1242. * Hide an aside element for a particular section
  1243. *
  1244. * @method hide
  1245. *
  1246. * @param {string} Element query selector
  1247. * @param {string} Value for counter
  1248. */
  1249. var hide = function(section_id, aside_id) {
  1250. var aside = lng.dom(ELEMENT.ASIDE + aside_id);
  1251. var section = lng.dom(ELEMENT.SECTION + section_id);
  1252. section.removeClass(CLASS.ASIDE).removeClass(CLASS.RIGHT);
  1253. setTimeout(function() {
  1254. var current_aside = ELEMENT.ASIDE + aside_id + '.' + CLASS.CURRENT;
  1255. lng.dom(current_aside).removeClass(CLASS.CURRENT);
  1256. }, 300);
  1257. };
  1258. var _classFromAside = function(aside) {
  1259. var aside_class = aside.attr(ATTRIBUTE.CLASS);
  1260. return aside_class || '';
  1261. };
  1262. return {
  1263. show: show,
  1264. hide: hide
  1265. };
  1266. })(LUNGO);
  1267. /**
  1268. * Initialize the <articles> layout of a certain <section>
  1269. *
  1270. * @namespace LUNGO.View
  1271. * @class Element
  1272. *
  1273. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  1274. */
  1275. LUNGO.View.Element = (function(lng, undefined) {
  1276. var ATTRIBUTE = lng.Constants.ATTRIBUTE;
  1277. var BINDING = lng.Constants.BINDING;
  1278. var SELECTORS = {
  1279. BUBBLE: '.bubble.count',
  1280. PROGRESS_VALUE: ' .value',
  1281. PROGRESS_PERCENTAGE: ' .labels span:last-child',
  1282. PROGRESS_DESCRIPTION: ' .labels span:first-child'
  1283. };
  1284. /**
  1285. * Set a counter to the element
  1286. *
  1287. * @method count
  1288. *
  1289. * @param {string} Element query selector
  1290. * @param {number} Value for counter
  1291. */
  1292. var count = function(selector, count) {
  1293. var element = lng.dom(selector);
  1294. if (element) {
  1295. if (count > 0) {
  1296. _setBubble(element, count);
  1297. } else {
  1298. element.children(SELECTORS.BUBBLE).remove();
  1299. }
  1300. }
  1301. };
  1302. /**
  1303. * Set a progress to the element
  1304. *
  1305. * @method progress
  1306. *
  1307. * @param {string} Element query selector
  1308. * @param {number} Percentage
  1309. * @param {boolean} Show the labels: description and current percentage
  1310. * @param {string} Description
  1311. */
  1312. var progress = function(selector, percentage, with_labels, description) {
  1313. var element = lng.dom(selector);
  1314. if (element) {
  1315. percentage += ATTRIBUTE.PERCENT;
  1316. lng.dom(selector + SELECTORS.PROGRESS_VALUE).style(ATTRIBUTE.WIDTH, percentage);
  1317. _setProgressLabel(selector + SELECTORS.PROGRESS_PERCENTAGE, with_labels, percentage);
  1318. _setProgressLabel(selector + SELECTORS.PROGRESS_DESCRIPTION, with_labels, description);
  1319. }
  1320. };
  1321. var _setBubble = function(element, count) {
  1322. var bubbles = element.children(SELECTORS.BUBBLE);
  1323. var total_bubbles = bubbles.length;
  1324. if (total_bubbles > 0) {
  1325. bubbles.html(count);
  1326. } else {
  1327. var count_html = LUNGO.Attributes.Data.Count.html;
  1328. var html_binded = count_html.replace(BINDING.START + BINDING.KEY + BINDING.END, count);
  1329. element.append(html_binded);
  1330. }
  1331. };
  1332. var _setProgressLabel = function(selector, with_labels, attribute) {
  1333. lng.dom(selector).html((with_labels) ? attribute : ATTRIBUTE.EMPTY);
  1334. };
  1335. return {
  1336. count: count,
  1337. progress: progress
  1338. };
  1339. })(LUNGO);
  1340. /**
  1341. * Object with data-attributes (HTML5) with a special <markup>
  1342. *
  1343. * @namespace LUNGO.Attributes
  1344. * @class Data
  1345. *
  1346. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  1347. * @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
  1348. */
  1349. LUNGO.Attributes.Data = {
  1350. Search: {
  1351. tag: 'search',
  1352. selector: '.list',
  1353. html: '<li class="search {{value}}"><input type="search" placeholder="Search..."><a href="#" class="button" data-icon="search"></a></li>'
  1354. },
  1355. Count: {
  1356. tag: 'count',
  1357. selector: '*',
  1358. html: '<span class="bubble count">{{value}}</span>'
  1359. },
  1360. Search: {
  1361. tag: 'search',
  1362. selector: '*',
  1363. html: '<input type="search" placeholder="{{value}}"/><a href="#" class="button" data-icon="search"></a>'
  1364. },
  1365. Progress: {
  1366. tag: 'progress',
  1367. selector: '*',
  1368. html: '<div class="progress" id="yeal">\
  1369. <span class="labels"><span></span><span></span></span>\
  1370. <span class="bar"><span class="value" style="width:{{value}};"><span class="glow"></span></span></span>\
  1371. </div>'
  1372. },
  1373. Label: {
  1374. tag: 'label',
  1375. selector: 'a',
  1376. html: '<abbr>{{value}}</abbr>'
  1377. },
  1378. Icon: {
  1379. tag: 'icon',
  1380. selector: '*',
  1381. html: '<span class="icon {{value}}"></span>'
  1382. },
  1383. Image: {
  1384. tag: 'image',
  1385. selector: '*',
  1386. html: '<img src="{{value}}" class="icon" />'
  1387. },
  1388. Title: {
  1389. tag: 'title',
  1390. selector: 'header, footer, article',
  1391. html: '<span class="title">{{value}}</span>'
  1392. },
  1393. Back: {
  1394. tag: 'back',
  1395. selector: 'header, footer',
  1396. html: '<a href="#back" data-target="section" class="onleft button default"><span class="icon {{value}}"></span></a>'
  1397. }
  1398. };
  1399. /**
  1400. * Temporary cache system
  1401. *
  1402. * @namespace LUNGO.Data
  1403. * @class Cache
  1404. *
  1405. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  1406. * @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
  1407. */
  1408. LUNGO.Data.Cache = (function(lng, undefined) {
  1409. var _cache = {};
  1410. /**
  1411. * Sets in the LungoJS cache system a new key/value
  1412. *
  1413. * @method set
  1414. *
  1415. * @param {string} Key for the new value
  1416. * @param {object} Type of environment: DESKTOP_ENVIRONMENT or MOBILE_ENVIRONMENT
  1417. */
  1418. var set = function(key, value) {
  1419. if (exists(key)) {
  1420. _cache[key] = lng.Core.mix(get(key), value);
  1421. } else {
  1422. _cache[key] = value;
  1423. }
  1424. };
  1425. /**
  1426. * Returns the value of a given key.
  1427. *
  1428. * @method get
  1429. *
  1430. * @param {string} Key in LungoJS Cache System
  1431. * @param {string} [OPTIONAL] Subkey in LungoJS Cache System
  1432. * @return {object} Value
  1433. */
  1434. var get = function(key, value) {
  1435. if (arguments.length === 1) {
  1436. return _cache[key];
  1437. } else {
  1438. return (_cache[arguments[0]]) ? _cache[arguments[0]][arguments[1]] : undefined;
  1439. }
  1440. };
  1441. /**
  1442. * Removes the instance in LungoJs Cache System of a given key
  1443. *
  1444. * @method remove
  1445. *
  1446. * @param {string} Key in LungoJS Cache System
  1447. * @param {string} [OPTIONAL] Subkey in LungoJS Cache System
  1448. */
  1449. var remove = function(key, value) {
  1450. if (arguments.length === 1) {
  1451. delete _cache[key];
  1452. } else {
  1453. delete _cache[arguments[0]][arguments[1]];
  1454. }
  1455. };
  1456. /**
  1457. * Returns the existence of a key in LungoJs Cache System
  1458. *
  1459. * @method exists
  1460. *
  1461. * @param {String} Key in LungoJS Cache System
  1462. * @return {Boolean} true if exists, false if not
  1463. */
  1464. var exists = function(key) {
  1465. return (_cache[key]) ? true : false;
  1466. };
  1467. return {
  1468. set: set,
  1469. get: get,
  1470. remove: remove,
  1471. exists: exists
  1472. };
  1473. })(LUNGO);
  1474. /**
  1475. * Wrapper for using WebSql (HTML5 feature)
  1476. *
  1477. * @namespace LUNGO.Data
  1478. * @class Sql
  1479. *
  1480. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  1481. * @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
  1482. */
  1483. LUNGO.Data.Sql = (function(lng, undefined) {
  1484. var ERROR = lng.Constants.ERROR;
  1485. var CONFIG = {
  1486. name: 'lungo_db',
  1487. version: '1.0',
  1488. size: 65536,
  1489. schema: []
  1490. };
  1491. var db = null;
  1492. /**
  1493. * Initialize the SQLite storage (HTML5 Feature)
  1494. *
  1495. * @method init
  1496. *
  1497. * @param {object} Configuration for the Database
  1498. */
  1499. var init = function(db_config) {
  1500. CONFIG = lng.Core.mix(CONFIG, db_config);
  1501. db = openDatabase(CONFIG.name, CONFIG.version, CONFIG.name, CONFIG.size);
  1502. if (db) {
  1503. _createSchema();
  1504. } else {
  1505. lng.Core.log(3, ERROR.DATABASE);
  1506. }
  1507. };
  1508. /**
  1509. * Select a data set of a given table and based on a selection object
  1510. *
  1511. * @method select
  1512. *
  1513. * @param {string} Name of the table in the database
  1514. * @param {object} [OPTIONAL] Object selection condition
  1515. * @param {Function} Callback when the process is complete
  1516. */
  1517. var select = function(table, where_obj, callback) {
  1518. var where = (where_obj) ? ' WHERE ' + _convertToSql(where_obj, 'AND') : '';
  1519. execute('SELECT * FROM ' + table + where, function(rs) {
  1520. var result = [];
  1521. for (var i = 0, len = rs.rows.length; i < len; i++) {
  1522. result.push(rs.rows.item(i));
  1523. }
  1524. _callbackResponse(callback, result);
  1525. });
  1526. };
  1527. /**
  1528. * Inserts a data set of a given table and based on a data object
  1529. *
  1530. * @method insert
  1531. *
  1532. * @param {string} Name of the table in the database
  1533. * @param {object} Object (or Array of objects) to insert in table
  1534. */
  1535. var insert = function(table, data, callback) {
  1536. if (lng.Core.toType(data) === 'object') {
  1537. _insertRow(table, data);
  1538. } else {
  1539. for (row in data) {
  1540. _insertRow(table, data[row]);
  1541. }
  1542. }
  1543. };
  1544. /**
  1545. * Updates a data set of a given table and based on a data object and
  1546. * an optional selection object
  1547. *
  1548. * @method update
  1549. *
  1550. * @param {string} Name of the table in the database
  1551. * @param {object} Data object to update in table
  1552. * @param {object} [OPTIONAL] Object selection condition
  1553. */
  1554. var update = function(table, data_obj, where_obj, callback) {
  1555. var sql = 'UPDATE ' + table + ' SET ' + _convertToSql(data_obj, ',');
  1556. if (where_obj) sql += ' WHERE ' + _convertToSql(where_obj, 'AND');
  1557. execute(sql);
  1558. };
  1559. /**
  1560. * Delete a data set of a given table and based on a selection object
  1561. *
  1562. * @method drop
  1563. *
  1564. * @param {string} Name of the table in the database
  1565. * @param {object} [OPTIONAL] Object selection condition
  1566. */
  1567. var drop = function(table, where_obj, callback) {
  1568. var where = (where_obj) ? ' WHERE ' + _convertToSql(where_obj, 'AND') : '';
  1569. execute('DELETE FROM ' + table + where + ';');
  1570. };
  1571. /**
  1572. * Executes a SQL statement in the SQLite storage
  1573. *
  1574. * @method execute
  1575. *
  1576. * @param {string} SQL statement
  1577. * @param {Function} Callback when the process is complete
  1578. */
  1579. var execute = function(sql, callback) {
  1580. lng.Core.log(1, 'lng.Data.Sql >> ' + sql);
  1581. db.transaction( function(transaction) {
  1582. transaction.executeSql(sql, [], function(transaction, rs) {
  1583. _callbackResponse(callback, rs);
  1584. }, function(transaction, error) {
  1585. transaction.executedQuery = sql;
  1586. _throwError.apply(null, arguments);
  1587. });
  1588. });
  1589. };
  1590. var _createSchema = function() {
  1591. var schema = CONFIG.schema;
  1592. var schema_len = schema.length;
  1593. if (!schema_len) return;
  1594. for (var i = 0; i < schema_len; i++) {
  1595. var current = schema[i];
  1596. _regenerateTable(current);
  1597. _createTable(current.name, current.fields);
  1598. }
  1599. };
  1600. var _createTable = function(table, fields) {
  1601. var sql_fields = '';
  1602. for (var field in fields) {
  1603. if (lng.Core.isOwnProperty(fields, field)) {
  1604. if (sql_fields) sql_fields += ', ';
  1605. sql_fields += field + ' ' + fields[field];
  1606. }
  1607. }
  1608. execute('CREATE TABLE IF NOT EXISTS ' + table + ' (' + sql_fields + ');');
  1609. };
  1610. var _regenerateTable = function(table) {
  1611. if (table.drop === true) {
  1612. _dropTable(table.name);
  1613. }
  1614. };
  1615. var _dropTable = function(table) {
  1616. execute('DROP TABLE IF EXISTS ' + table);
  1617. };
  1618. var _convertToSql = function(fields, separator) {
  1619. var sql = '';
  1620. for (var field in fields) {
  1621. if (lng.Core.isOwnProperty(fields, field)) {
  1622. var value = fields[field];
  1623. if (sql) sql += ' ' + separator + ' ';
  1624. sql += field + '=';
  1625. sql += (isNaN(value)) ? '"' + value + '"' : value;
  1626. }
  1627. }
  1628. return sql;
  1629. };
  1630. var _callbackResponse = function(callback, response) {
  1631. if (lng.Core.toType(callback) === 'function') {
  1632. setTimeout(callback, 100, response);
  1633. }
  1634. };
  1635. var _insertRow = function(table, row) {
  1636. var fields = '';
  1637. var values = '';
  1638. for (var field in row) {
  1639. if (lng.Core.isOwnProperty(row, field)) {
  1640. var value = row[field];
  1641. fields += (fields) ? ', ' + field : field;
  1642. if (values) values += ', ';
  1643. values += (isNaN(value)) ? '"' + value + '"' : value;
  1644. }
  1645. }
  1646. execute('INSERT INTO ' + table + ' (' + fields + ') VALUES (' + values + ')');
  1647. };
  1648. var _throwError = function(transaction, error) {
  1649. lng.Core.log(3, 'lng.Data.Sql >> ' + error.code + ': ' + error.message + ' \n Executed query: ' + transaction.executedQuery);
  1650. };
  1651. return {
  1652. init: init,
  1653. select: select,
  1654. insert: insert,
  1655. update: update,
  1656. drop: drop,
  1657. execute: execute
  1658. };
  1659. })(LUNGO);
  1660. /**
  1661. * Wrapper for using LocalStorage & SessionStorage (HTML5 Feature)
  1662. *
  1663. * @namespace LUNGO.Data
  1664. * @class Storage
  1665. *
  1666. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  1667. * @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
  1668. */
  1669. LUNGO.Data.Storage = (function(lng, undefined) {
  1670. var STORAGE = {
  1671. PERSISTENT: 'localStorage',
  1672. SESSION: 'sessionStorage'
  1673. };
  1674. /**
  1675. * Wrapper for SessionStorage
  1676. *
  1677. * @method persistent
  1678. *
  1679. * @param {string} Key
  1680. * @param {object} Value
  1681. * @return {string} If no value assigned returns the value of established key
  1682. */
  1683. var persistent = function(key, value) {
  1684. return _handler(STORAGE.PERSISTENT, key, value);
  1685. };
  1686. /**
  1687. * Wrapper for SessionStorage
  1688. *
  1689. * @method session
  1690. *
  1691. * @param {string} Key
  1692. * @param {object} Value
  1693. * @return {string} If no value assigned returns the value of established key
  1694. */
  1695. var session = function(key, value) {
  1696. return _handler(STORAGE.SESSION, key, value);
  1697. };
  1698. var _handler = function(storage, key, value) {
  1699. var storage = window[storage];
  1700. if (value) {
  1701. _saveKey(storage, key, value);
  1702. } else {
  1703. return _getKey(storage, key, value);
  1704. }
  1705. };
  1706. var _saveKey = function(storage, key, value) {
  1707. value = JSON.stringify(value);
  1708. storage.setItem(key, value);
  1709. };
  1710. var _getKey = function(storage, key, value) {
  1711. value = storage.getItem(key);
  1712. return JSON.parse(value);
  1713. };
  1714. return {
  1715. session: session,
  1716. persistent: persistent
  1717. };
  1718. })(LUNGO);
  1719. /**
  1720. * Boot for a new LungoJS Application instance
  1721. *
  1722. * @namespace LUNGO
  1723. * @class App
  1724. *
  1725. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  1726. * @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
  1727. */
  1728. LUNGO.Boot = (function(lng, undefined) {
  1729. return function() {
  1730. lng.Boot.Resources.start();
  1731. lng.Boot.Layout.start();
  1732. lng.Boot.Events.start();
  1733. lng.Boot.Data.start();
  1734. lng.Boot.Section.start();
  1735. lng.Boot.Article.start();
  1736. lng.Boot.Stats.start();
  1737. };
  1738. })(LUNGO);
  1739. /**
  1740. * Load Resources
  1741. *
  1742. * @namespace LUNGO.Boot
  1743. * @class Resources
  1744. *
  1745. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  1746. */
  1747. LUNGO.Boot.Resources = (function(lng, $$, undefined) {
  1748. var ELEMENT = lng.Constants.ELEMENT;
  1749. var ERROR = lng.Constants.ERROR;
  1750. var RESOURCE = {
  1751. SECTION: 'sections',
  1752. TEMPLATE: 'templates',
  1753. SCRIPT: 'scripts'
  1754. };
  1755. /**
  1756. * Start loading async sections (local & remote)
  1757. *
  1758. * @method start
  1759. *
  1760. */
  1761. var start = function() {
  1762. var resources = lng.App.get('resources');
  1763. for (resource_key in resources) {
  1764. _loadResources(resource_key, resources[resource_key]);
  1765. }
  1766. };
  1767. var _loadResources = function(resource_key, resources, callback) {
  1768. for (index in resources) {
  1769. var url = _parseUrl(resources[index], resource_key);
  1770. try {
  1771. var response = _loadAsyncResource(url);
  1772. _factoryResources(resource_key, response);
  1773. } catch(error) {
  1774. lng.Core.log(3, ERROR.LOADING_RESOURCE + ' ' + error);
  1775. }
  1776. }
  1777. };
  1778. var _parseUrl = function(section_url, folder) {
  1779. return (/http/.test(section_url)) ? section_url : 'app/' + folder + '/' + section_url;
  1780. };
  1781. var _loadAsyncResource = function(url) {
  1782. return $$.ajax({
  1783. url: url,
  1784. async: false,
  1785. dataType: 'html',
  1786. error: function() {
  1787. console.error('[ERROR] Loading url', arguments);
  1788. }
  1789. });
  1790. };
  1791. var _factoryResources = function(resource_key, response) {
  1792. switch(resource_key) {
  1793. case RESOURCE.SECTION:
  1794. _pushSectionInLayout(response);
  1795. break;
  1796. case RESOURCE.TEMPLATE:
  1797. _createTemplate(response);
  1798. break;
  1799. case RESOURCE.SCRIPT:
  1800. break;
  1801. }
  1802. };
  1803. var _pushSectionInLayout = function(section) {
  1804. if (lng.Core.toType(section) === 'string') {
  1805. lng.dom(ELEMENT.BODY).append(section);
  1806. }
  1807. };
  1808. var _createTemplate = function(markup) {
  1809. var div = document.createElement(ELEMENT.DIV);
  1810. div.innerHTML = markup;
  1811. var template_id = lng.dom(div.firstChild).data('template');
  1812. if (template_id) {
  1813. lng.View.Template.create(template_id, markup);
  1814. }
  1815. };
  1816. return {
  1817. start: start
  1818. };
  1819. })(LUNGO, Quo);
  1820. /**
  1821. * Save in LungoJS.com the use of the service for further ranking
  1822. *
  1823. * @namespace LUNGO.Boot
  1824. * @class Stats
  1825. *
  1826. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  1827. * @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
  1828. */
  1829. LUNGO.Boot.Stats = (function(lng, undefined) {
  1830. /**
  1831. * Analizing if it's run in Mobile Phone and changing the type of event to subscribe.
  1832. *
  1833. * @method start
  1834. */
  1835. var start = function() {
  1836. if (lng.Core.isMobile()) {
  1837. _saveStats();
  1838. }
  1839. };
  1840. /**
  1841. * Save in LungoJS.com the use of the service for further ranking
  1842. *
  1843. * @method _saveStatsInLungoJS
  1844. */
  1845. var _saveStats = function() {
  1846. lng.Service.post( 'http://www.lungojs.com/stats/', {
  1847. name: lng.App.get('name'),
  1848. version: lng.App.get('version'),
  1849. icon: lng.App.get('icon')
  1850. }, function(response) {});
  1851. };
  1852. return {
  1853. start: start
  1854. };
  1855. })(LUNGO);
  1856. /**
  1857. * Initialize the Layout of LungoJS (if it's a mobile environment)
  1858. *
  1859. * @namespace LUNGO.Boot
  1860. * @class Layout
  1861. *
  1862. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  1863. */
  1864. LUNGO.Boot.Layout = (function(lng, undefined) {
  1865. var _window = null;
  1866. var _document = null;
  1867. var ELEMENT = lng.Constants.ELEMENT;
  1868. var ATTRIBUTE = lng.Constants.ATTRIBUTE;
  1869. /**
  1870. * Initializes the automatic subscription events by markup of the project.
  1871. *
  1872. * @method init
  1873. *
  1874. */
  1875. var start = function() {
  1876. if (lng.Core.isMobile()) {
  1877. _window = window;
  1878. _document = _window.document;
  1879. _resizeLayout();
  1880. }
  1881. };
  1882. var _resizeLayout = function() {
  1883. if (_window.innerHeight == 356) {
  1884. var _height = 416;
  1885. lng.dom(ELEMENT.BODY).style(ATTRIBUTE.HEIGHT, _height + ATTRIBUTE.PIXEL);
  1886. _hideNavigationBar();
  1887. }
  1888. };
  1889. var _hideNavigationBar = function() {
  1890. if( !location.hash || !_window.addEventListener ){
  1891. _window.scrollTo( 0, 1 );
  1892. var scrollTop = 1,
  1893. //reset to 0 on bodyready, if needed
  1894. bodycheck = setInterval(function(){
  1895. if( _document.body ){
  1896. clearInterval( bodycheck );
  1897. scrollTop = 'scrollTop' in _document.body ? _document.body.scrollTop : 1;
  1898. _window.scrollTo( 0, scrollTop === 1 ? 0 : 1 );
  1899. }
  1900. }, 15 );
  1901. _window.addEventListener('load', function(){
  1902. setTimeout(function(){
  1903. _window.scrollTo( 0, scrollTop === 1 ? 0 : 1 );
  1904. }, 0);
  1905. }, false );
  1906. }
  1907. };
  1908. return {
  1909. start: start
  1910. };
  1911. })(LUNGO);
  1912. /**
  1913. * Initialize the <article> element
  1914. *
  1915. * @namespace LUNGO.Boot
  1916. * @class Article
  1917. *
  1918. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  1919. * @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
  1920. */
  1921. LUNGO.Boot.Article = (function(lng, undefined) {
  1922. var ATTRIBUTE = lng.Constants.ATTRIBUTE;
  1923. var ELEMENT = lng.Constants.ELEMENT;
  1924. var SELECTORS = {
  1925. LIST_IN_ARTICLE: 'article.list, aside.list',
  1926. SCROLL_IN_ARTICLE: '.scrollable',
  1927. CHECKBOX_IN_ARTICLE: '.checkbox, .radio'
  1928. };
  1929. /**
  1930. * Initializes the markup elements of an article
  1931. *
  1932. * @method init
  1933. */
  1934. var start = function() {
  1935. _initElement(SELECTORS.LIST_IN_ARTICLE, _createListElement);
  1936. _initElement(SELECTORS.SCROLL_IN_ARTICLE, _createScrollElement);
  1937. _initElement(SELECTORS.CHECKBOX_IN_ARTICLE, _createCheckboxElement);
  1938. };
  1939. var _initElement = function(selector, callback) {
  1940. var found_elements = lng.dom(selector);
  1941. for (var i = 0, len = found_elements.length; i < len; i++) {
  1942. var element = lng.dom(found_elements[i]);
  1943. lng.Core.execute(callback, element);
  1944. }
  1945. };
  1946. var _createListElement = function(article) {
  1947. if (article.children().length === 0) {
  1948. var article_id = article.attr(ATTRIBUTE.ID);
  1949. article.append(ELEMENT.LIST);
  1950. }
  1951. };
  1952. var _createScrollElement = function(scroll) {
  1953. var scroll_id = scroll.attr(ATTRIBUTE.ID);
  1954. lng.View.Scroll.init(scroll_id);
  1955. };
  1956. var _createCheckboxElement = function(checkbox) {
  1957. checkbox.append(ELEMENT.SPAN);
  1958. };
  1959. return {
  1960. start: start
  1961. };
  1962. })(LUNGO);
  1963. /**
  1964. * Make an analysis of Data attributes in HTML elements and creates a <markup>
  1965. * based on each data type.
  1966. *
  1967. * @namespace LUNGO.Boot
  1968. * @class Data
  1969. *
  1970. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  1971. * @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
  1972. */
  1973. LUNGO.Boot.Data = (function(lng, undefined) {
  1974. /**
  1975. * Initialize the <markup> data-attributes analisys
  1976. *
  1977. * @method init
  1978. *
  1979. *
  1980. */
  1981. var start = function() {
  1982. var attributes = lng.Attributes.Data;
  1983. for (var attribute in attributes) {
  1984. if (lng.Core.isOwnProperty(attributes, attribute)) {
  1985. _findElements(attributes[attribute]);
  1986. }
  1987. }
  1988. };
  1989. var _findElements = function(attribute) {
  1990. var elements = lng.dom(attribute.selector);
  1991. for (var i = 0, len = elements.length; i < len; i++) {
  1992. var element = lng.dom(elements[i]);
  1993. lng.View.Template.Binding.dataAttribute(element, attribute);
  1994. }
  1995. };
  1996. return {
  1997. start: start
  1998. };
  1999. })(LUNGO);
  2000. /**
  2001. * Initialize the automatic DOM UI events
  2002. *
  2003. * @namespace LUNGO.Boot
  2004. * @class Events
  2005. *
  2006. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  2007. * @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
  2008. */
  2009. LUNGO.Boot.Events = (function(lng, undefined) {
  2010. var ATTRIBUTE = lng.Constants.ATTRIBUTE;
  2011. var CLASS = lng.Constants.CLASS;
  2012. var ELEMENT = lng.Constants.ELEMENT;
  2013. var SELECTORS = {
  2014. HREF_TARGET: 'a[href][data-target]',
  2015. HREF_TARGET_FROM_ASIDE: 'aside a[href][data-target]'
  2016. };
  2017. /**
  2018. * Initializes the automatic subscription events by markup of the project.
  2019. *
  2020. * @method init
  2021. *
  2022. */
  2023. var start = function() {
  2024. var touch_move_event = 'touchmove';
  2025. var resize = 'resize';
  2026. //@ToDo: Error with input type="range"
  2027. //lng.dom(document).on(touch_move_event, _iScroll);
  2028. lng.dom(window).on(resize, _changeOrientation);
  2029. lng.dom(SELECTORS.HREF_TARGET_FROM_ASIDE).tap(_loadTargetFromAside);
  2030. lng.dom(SELECTORS.HREF_TARGET).tap(_loadTarget);
  2031. lng.Fallback.androidButtons();
  2032. };
  2033. var _iScroll = function(event) {
  2034. event.preventDefault();
  2035. };
  2036. var _changeOrientation = function(event) {
  2037. lng.View.Resize.toolbars();
  2038. };
  2039. var _loadTargetFromAside = function(event) {
  2040. var link = lng.dom(this);
  2041. var aside_id = '#' + link.parent(ELEMENT.ASIDE).attr(ATTRIBUTE.ID);
  2042. var section_id = '#' + lng.dom('section.aside, section.current').first().attr(ATTRIBUTE.ID);
  2043. if (link.data(ATTRIBUTE.TARGET) === ELEMENT.ARTICLE) {
  2044. lng.dom(ELEMENT.ASIDE + aside_id + ' ' + SELECTORS.HREF_TARGET).removeClass(CLASS.CURRENT);
  2045. link.addClass(CLASS.CURRENT);
  2046. }
  2047. _hideAsideIfNecesary(section_id, aside_id);
  2048. };
  2049. var _loadTarget = function(event) {
  2050. var link = lng.dom(this);
  2051. _selectTarget(link);
  2052. event.preventDefault();
  2053. };
  2054. var _selectTarget = function(link) {
  2055. var target_type = link.data(ATTRIBUTE.TARGET);
  2056. switch(target_type) {
  2057. case ELEMENT.SECTION:
  2058. var target_id = link.attr(ATTRIBUTE.HREF);
  2059. _goSection(target_id);
  2060. break;
  2061. case ELEMENT.ARTICLE:
  2062. _goArticle(link);
  2063. break;
  2064. case ELEMENT.ASIDE:
  2065. _goAside(link);
  2066. break;
  2067. }
  2068. };
  2069. var _goSection = function(id) {
  2070. id = lng.Core.parseUrl(id);
  2071. if (id === '#back') {
  2072. lng.Router.back();
  2073. } else {
  2074. lng.Router.section(id);
  2075. }
  2076. };
  2077. var _goArticle = function(element) {
  2078. var section_id = lng.Router.History.current();
  2079. var article_id = element.attr(ATTRIBUTE.HREF);
  2080. lng.Router.article(section_id, article_id);
  2081. };
  2082. var _goAside = function(element) {
  2083. var section_id = lng.Router.History.current();
  2084. var aside_id = element.attr(ATTRIBUTE.HREF);
  2085. lng.Router.aside(section_id, aside_id);
  2086. };
  2087. var _hideAsideIfNecesary = function(section_id, aside_id) {
  2088. if (window.innerWidth < 768) {
  2089. lng.View.Aside.hide(section_id, aside_id);
  2090. }
  2091. };
  2092. return {
  2093. start: start
  2094. };
  2095. })(LUNGO);
  2096. /**
  2097. * Initialize the <section> element
  2098. *
  2099. * @namespace LUNGO.Boot
  2100. * @class Section
  2101. *
  2102. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  2103. * @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
  2104. */
  2105. LUNGO.Boot.Section = (function(lng, undefined) {
  2106. var ELEMENT = lng.Constants.ELEMENT;
  2107. var CLASS = lng.Constants.CLASS;
  2108. var ATTRIBUTE = lng.Constants.ATTRIBUTE;
  2109. /**
  2110. * Initializes all <section>s of the project
  2111. *
  2112. * @method init
  2113. */
  2114. var start = function() {
  2115. var sections = lng.dom(ELEMENT.SECTION);
  2116. _initFirstSection(sections);
  2117. _initAllSections(sections);
  2118. lng.View.Resize.toolbars();
  2119. };
  2120. var _initFirstSection = function(sections) {
  2121. var first_section = sections.first();
  2122. var first_section_id = '#' + first_section.attr(ATTRIBUTE.ID);
  2123. first_section.addClass(CLASS.CURRENT);
  2124. lng.Router.History.add(first_section_id);
  2125. };
  2126. var _initAllSections = function(sections) {
  2127. lng.Fallback.positionFixed(sections);
  2128. for (var i = 0, len = sections.length; i < len; i++) {
  2129. var section = lng.dom(sections[i]);
  2130. _initArticles(section);
  2131. }
  2132. };
  2133. var _initArticles = function(section) {
  2134. var first_article = section.children(ELEMENT.ARTICLE).first();
  2135. first_article.addClass(CLASS.CURRENT);
  2136. var first_article_id = first_article.attr(ATTRIBUTE.ID);
  2137. var section_id = '#' + section.attr(ATTRIBUTE.ID);
  2138. lng.View.Article.showReferenceLinks(section_id, first_article_id);
  2139. };
  2140. return {
  2141. start: start
  2142. };
  2143. })(LUNGO);