lungo-1.0.4.js 55 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117
  1. /**
  2. *
  3. * /$$
  4. * | $$
  5. * | $$ /$$ /$$ /$$$$$$$ /$$$$$$ /$$$$$$
  6. * | $$ | $$ | $$| $$__ $$ /$$__ $$ /$$__ $$
  7. * | $$ | $$ | $$| $$ \ $$| $$ \ $$| $$ \ $$
  8. * | $$ | $$ | $$| $$ | $$| $$ | $$| $$ | $$
  9. * | $$$$$$$$| $$$$$$/| $$ | $$| $$$$$$$| $$$$$$/
  10. * |________/ \______/ |__/ |__/ \____ $$ \______/
  11. * /$$ \ $$
  12. * | $$$$$$/
  13. * \______/
  14. *
  15. * @copyright 2011 TapQuo Inc (c)
  16. * @license http://www.github.com/tapquo/lungo/blob/master/LICENSE.txt
  17. * @version 1.0.4
  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.0.4';
  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. /**
  31. * Lungo sandbox APP initialization
  32. *
  33. * @namespace LUNGO
  34. * @class App
  35. *
  36. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  37. * @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
  38. */
  39. LUNGO.App = (function(lng, undefined) {
  40. var default_config = {
  41. id: 1,
  42. name: 'lungo_app',
  43. version: 1.0,
  44. icon: ''
  45. };
  46. /**
  47. * Initializes all LungoJS system: setting properties for the application,
  48. * subscribing to automatic events, initializing sections & articles
  49. * and stating the title.
  50. *
  51. * @method init
  52. *
  53. * @param {object} Application configuration properties
  54. */
  55. var init = function(app_config) {
  56. default_config = lng.Core.mix(default_config, app_config);
  57. lng.Boot();
  58. };
  59. var get = function(property) {
  60. return default_config[property];
  61. };
  62. return {
  63. init: init,
  64. get: get
  65. };
  66. })(LUNGO);
  67. /**
  68. * Set environment (Desktop or Mobile) automatically, depending on the
  69. * environment the subscribed events wil be different.
  70. *
  71. * @namespace LUNGO
  72. * @class Environment
  73. *
  74. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  75. * @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
  76. */
  77. LUNGO.Environment = (function(lng, undefined) {
  78. var MOBILE_ENVIRONMENT = 'mobile';
  79. var DESKTOP_ENVIRONMENT = 'desktop';
  80. var _environment = DESKTOP_ENVIRONMENT;
  81. /**
  82. * Analizing if it's run in Mobile Phone and changing the type of event to subscribe.
  83. *
  84. * @method start
  85. */
  86. var start = function() {
  87. if (lng.Core.isMobile()) {
  88. _environment = MOBILE_ENVIRONMENT;
  89. _saveStatsInLungoJS();
  90. }
  91. };
  92. /**
  93. * Gets the current environment for LungoJS
  94. *
  95. * @method init
  96. *
  97. * @return {String} Current environment enumerator
  98. */
  99. var current = function() {
  100. return _environment;
  101. };
  102. /**
  103. * Returns whether the development environment is in desktop mode
  104. *
  105. * @method isDesktop
  106. *
  107. * @return {Boolean} True if is in DESKTOP_ENVIRONMENT
  108. */
  109. var isDesktop = function() {
  110. return (_environment === DESKTOP_ENVIRONMENT) ? true : false;
  111. };
  112. /**
  113. * Save in LungoJS.com the use of the service for further ranking
  114. *
  115. * @method _saveStatsInLungoJS
  116. */
  117. var _saveStatsInLungoJS = function() {
  118. lng.Service.post( 'http://www.lungojs.com/stats/', {
  119. name: lng.App.get('name'),
  120. version: lng.App.get('version'),
  121. icon: lng.App.get('icon')
  122. });
  123. }
  124. return {
  125. start: start,
  126. current: current,
  127. isDesktop: isDesktop
  128. };
  129. })(LUNGO);
  130. /**
  131. * Contains all the common functions used in Lungo.
  132. *
  133. * @namespace LUNGO
  134. * @class Core
  135. *
  136. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  137. * @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
  138. */
  139. LUNGO.Core = (function(lng, $, undefined) {
  140. var ARRAY_PROTO = Array.prototype;
  141. var OBJ_PROTO = Object.prototype;
  142. var SUPPORTED_OS = ['ios', 'android', 'blackberry', 'webos'];
  143. /**
  144. * Console system to display messages when you are in debug mode.
  145. *
  146. * @method log
  147. *
  148. * @param {number} Severity based in (1)Log, (2)Warn, (>2)Error
  149. * @param {string} Message to show in console
  150. */
  151. var log = function(severity, message) {
  152. if (lng.Environment.isDesktop()) {
  153. console[(severity === 1) ? 'log' : (severity === 2) ? 'warn' : 'error'](message);
  154. } else {
  155. // @todo : send to the server
  156. }
  157. };
  158. /**
  159. * Executes callbacks based on the parameters received.
  160. *
  161. * @method execute
  162. *
  163. * @param {Function} callback to execute
  164. */
  165. var execute = function() {
  166. var args = toArray(arguments);
  167. var callback = args.shift();
  168. if (toType(callback) === 'function') {
  169. callback.apply(null, args);
  170. }
  171. };
  172. /**
  173. * Creates a new function that, when called, itself calls this function in
  174. * the context of the provided this value, with a given sequence of arguments
  175. * preceding any provided when the new function was called.
  176. *
  177. * @method bind
  178. *
  179. * @param {object} object to which the 'this' can refer in the new function when the new function is called.
  180. * @param {Function} method A function object.
  181. */
  182. var bind = function(object, method) {
  183. return function() {
  184. return method.apply(object, toArray(arguments));
  185. };
  186. };
  187. /**
  188. * Copy from any number of objects and mix them all into a new object.
  189. * The implementation is simple; just loop through arguments and
  190. * copy every property of every object passed to the function.
  191. *
  192. * @method mix
  193. *
  194. * @param {object} arguments to mix them all into a new object.
  195. * @return {object} child a new object with all the objects from the arguments mixed.
  196. */
  197. var mix = function() {
  198. var child = child || {};
  199. for (var arg = 0, len = arguments.length; arg < len; arg++) {
  200. var argument = arguments[arg];
  201. for (var prop in argument) {
  202. if (isOwnProperty(argument, prop)) {
  203. child[prop] = argument[prop];
  204. }
  205. }
  206. }
  207. return child;
  208. };
  209. /**
  210. * Every object descended from Object inherits the hasOwnProperty method.
  211. * This method can be used to determine whether an object has the specified property
  212. * as a direct property of that object.
  213. *
  214. * @param {object} object to test for a property's existence inside itself.
  215. * @param {string} property the name of the property to test.
  216. * @return {boolean} indicating whether the object has the specified property.
  217. */
  218. var isOwnProperty = function(object, property) {
  219. return OBJ_PROTO.hasOwnProperty.call(object, property);
  220. };
  221. /**
  222. * Determine the internal JavaScript [[Class]] of an object.
  223. *
  224. * @param {object} obj to get the real type of itself.
  225. * @return {string} with the internal JavaScript [[Class]] of itself.
  226. */
  227. var toType = function(obj) {
  228. return OBJ_PROTO.toString.call(obj).match(/\s([a-z|A-Z]+)/)[1].toLowerCase();
  229. };
  230. /**
  231. * Convert an array-like object into a true JavaScript array.
  232. *
  233. * @param {object} obj Any object to turn into a native Array.
  234. * @return {object} The object is now a plain array.
  235. */
  236. var toArray = function(obj) {
  237. return ARRAY_PROTO.slice.call(obj, 0);
  238. };
  239. /**
  240. *
  241. *
  242. */
  243. var isMobile = function() {
  244. var result = false;
  245. for (var i = 0, len = SUPPORTED_OS.length; i < len && !result; i++) {
  246. var mobile_os = SUPPORTED_OS[i];
  247. $.os[mobile_os] && (result = true);
  248. }
  249. return result;
  250. };
  251. return {
  252. log: log,
  253. execute: execute,
  254. bind: bind,
  255. mix: mix,
  256. isOwnProperty: isOwnProperty,
  257. toType: toType,
  258. toArray: toArray,
  259. isMobile: isMobile
  260. };
  261. })(LUNGO, Zepto);
  262. /**
  263. * Lungo UI events Manager
  264. *
  265. * @namespace LUNGO
  266. * @class Event
  267. * @requires Zepto
  268. *
  269. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  270. * @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
  271. */
  272. LUNGO.Events = (function(lng, undefined) {
  273. var EVENTS = {
  274. mobile: {
  275. TOUCH_START: 'touchstart',
  276. TOUCH_MOVE: 'touchmove',
  277. TOUCH_END: 'touchend',
  278. TAP: 'tap',
  279. DOUBLE_TAP: 'doubletap',
  280. ORIENTATION_CHANGE: 'orientationchange'
  281. },
  282. desktop: {
  283. TOUCH_START: 'mousedown',
  284. TOUCH_MOVE: 'mousemove',
  285. TOUCH_END: 'mouseup',
  286. TAP: 'click',
  287. DOUBLE_TAP: 'dblclick',
  288. ORIENTATION_CHANGE: 'resize'
  289. }
  290. };
  291. var current_environment = lng.Environment.current();
  292. var current_events = EVENTS[current_environment];
  293. /**
  294. * Returns the touch event based on an enumeration of LungoJS
  295. * and the current environment
  296. *
  297. * @method get
  298. *
  299. * @param {string} Touch enumerator of LungoJS
  300. * @return {string} Touch event based on the current environment
  301. */
  302. var get = function(eventName) {
  303. return current_events[eventName];
  304. };
  305. return {
  306. get: get
  307. };
  308. })(LUNGO);
  309. /**
  310. * External Data & Services Manager
  311. *
  312. * @namespace LUNGO
  313. * @class Service
  314. * @requires Zepto
  315. *
  316. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  317. * @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
  318. */
  319. LUNGO.Service = (function(lng, $, undefined) {
  320. /**
  321. * Load data from the server using a HTTP GET request.
  322. *
  323. * @method get
  324. *
  325. * @param {string} Containing the URL to which the request is sent
  326. * @param {object} A map or string that is sent to the server with the request
  327. * @param {Function} [OPTIONAL] Callback function after the request
  328. */
  329. var get = function(url, data, callback) {
  330. var parameters = '?';
  331. for (var parameter in data) {
  332. if (lng.Core.isOwnProperty(data, parameter)) {
  333. if (parameters !== '?') parameters += '&';
  334. parameters += parameter + '=' + data[parameter];
  335. }
  336. }
  337. url = url + parameters;
  338. _ajax('GET', url, null, callback);
  339. };
  340. /**
  341. * Load data from the server using a HTTP POST request.
  342. *
  343. * @method post
  344. *
  345. * @param {string} Containing the URL to which the request is sent
  346. * @param {object} A map or string that is sent to the server with the request
  347. * @param {Function} [OPTIONAL] Callback function after the request
  348. */
  349. var post = function(url, data, callback) {
  350. _ajax('POST', url, data, callback);
  351. };
  352. var _ajax = function(type, url, data, callback, error) {
  353. $.ajax({
  354. type: type,
  355. url: url,
  356. data: data,
  357. dataType: 'json',
  358. success: function(response) {
  359. if (lng.Core.toType(callback) === 'function') {
  360. setTimeout(callback, 100, response);
  361. }
  362. },
  363. error: function(xhr, type) {
  364. if (error) {
  365. setTimeout(error, 100, result);
  366. }
  367. }
  368. });
  369. };
  370. return {
  371. get: get,
  372. post: post
  373. };
  374. })(LUNGO, Zepto);/**
  375. * Handles the <sections> and <articles> to show
  376. *
  377. * @namespace LUNGO
  378. * @class Router
  379. * @requires Zepto
  380. *
  381. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  382. * @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
  383. */
  384. LUNGO.Router = (function(lng, undefined) {
  385. var CSS_CLASSES = {
  386. SHOW: 'show',
  387. HIDE: 'hide'
  388. };
  389. /**
  390. * Navigate to a <section>.
  391. *
  392. * @method section
  393. *
  394. * @param {string} Id of the <section>
  395. */
  396. var section = function(section_id) {
  397. var section_id = (section_id.indexOf('#')) ? '#' + section_id : section_id;
  398. var target = 'section' + section_id;
  399. if (_existsTarget(target)) {
  400. lng.Dom.query(_getHistoryCurrent()).removeClass(CSS_CLASSES.SHOW).addClass(CSS_CLASSES.HIDE);
  401. lng.Dom.query(section_id).addClass(CSS_CLASSES.SHOW);
  402. lng.Router.History.add(section_id);
  403. }
  404. };
  405. /**
  406. * Displays the <article> in a particular <section>.
  407. *
  408. * @method article
  409. *
  410. * @param {string} <section> Id
  411. * @param {string} <article> Id
  412. */
  413. var article = function(section_id, article_id) {
  414. var target = section_id + ' article' + article_id;
  415. if (_existsTarget(target)) {
  416. lng.View.Article.show(section_id, article_id);
  417. }
  418. };
  419. /**
  420. * Return to previous section.
  421. *
  422. * @method back
  423. */
  424. var back = function() {
  425. lng.Dom.query(_getHistoryCurrent()).removeClass(CSS_CLASSES.SHOW);
  426. lng.Router.History.removeLast();
  427. lng.Dom.query(_getHistoryCurrent()).removeClass(CSS_CLASSES.HIDE).addClass(CSS_CLASSES.SHOW);
  428. };
  429. var _existsTarget = function(target) {
  430. var exists = false;
  431. if ($(target).length > 0) {
  432. exists = true;
  433. } else {
  434. lng.Core.log(3, 'Lungo.Router ERROR: The target ' + target + ' does not exists.');
  435. }
  436. return exists;
  437. }
  438. var _getHistoryCurrent = function() {
  439. return lng.Router.History.current();
  440. };
  441. return {
  442. section: section,
  443. article: article,
  444. back: back
  445. };
  446. })(LUNGO);
  447. /**
  448. * Stores the displayed <sections> as a historical.
  449. *
  450. * @namespace LUNGO.Router
  451. * @class History
  452. *
  453. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  454. * @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
  455. */
  456. LUNGO.Router.History = (function(undefined) {
  457. var _history = [];
  458. /**
  459. * Create a new element to the browsing history based on the current section id.
  460. *
  461. * @method add
  462. *
  463. * @param {string} Id of the section
  464. */
  465. var add = function(section_id) {
  466. if (section_id !== current()) {
  467. _history.push(section_id);
  468. }
  469. };
  470. /**
  471. * Returns the current browsing history section id.
  472. *
  473. * @method current
  474. *
  475. * @return {string} Current section id
  476. */
  477. var current = function() {
  478. return _history[_history.length - 1];
  479. };
  480. /**
  481. * Removes the current item browsing history.
  482. *
  483. * @method removeLast
  484. */
  485. var removeLast = function() {
  486. _history.length -= 1;
  487. };
  488. return {
  489. add: add,
  490. current: current,
  491. removeLast: removeLast
  492. };
  493. })();
  494. /**
  495. * Initialize the <articles> layout of a certain <section>
  496. *
  497. * @namespace LUNGO.View
  498. * @class Article
  499. *
  500. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  501. * @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
  502. */
  503. LUNGO.View.Article = (function(lng, undefined) {
  504. var SELECTORS = {
  505. ARTICLE: 'article',
  506. NAVIGATION_ITEM: 'a'
  507. };
  508. var CSS_CLASSES = {
  509. ACTIVE: 'current'
  510. };
  511. var show = function(section_id, article_id) {
  512. var nav_items = section_id + ' ' + SELECTORS.NAVIGATION_ITEM;
  513. _disableNavItems(nav_items);
  514. var current_nav_item = lng.Dom.query(nav_items + '[href="' + article_id + '"]');
  515. current_nav_item.addClass(CSS_CLASSES.ACTIVE);
  516. _setTitle(section_id, current_nav_item);
  517. _showContainer(section_id, article_id);
  518. };
  519. var _disableNavItems = function(items) {
  520. lng.Dom.query(items).removeClass(CSS_CLASSES.ACTIVE);
  521. };
  522. var _showContainer = function(section_id, article_id) {
  523. var section_articles = section_id + ' ' + SELECTORS.ARTICLE;
  524. lng.Dom.query(section_articles).removeClass(CSS_CLASSES.ACTIVE);
  525. lng.Dom.query(article_id).addClass(CSS_CLASSES.ACTIVE);
  526. };
  527. var _setTitle = function(id, item) {
  528. var title = item.data('title');
  529. if (title) {
  530. var section_title = id + ' header .title, ' + id + ' footer .title';
  531. lng.Dom.query(section_title).text(title);
  532. }
  533. };
  534. return {
  535. show: show
  536. };
  537. })(LUNGO);
  538. /**
  539. *
  540. *
  541. * @namespace LUNGO.View
  542. * @class Resize
  543. *
  544. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  545. * @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
  546. */
  547. LUNGO.View.Resize = (function(lng, undefined) {
  548. /**
  549. * Rezise a <scroll> element
  550. *
  551. * @method scroll
  552. *
  553. * @param {object} Object reference of a determinated <section>
  554. */
  555. var scroll = function(scroll) {
  556. var container = scroll.children().first();
  557. var child = container.children().first();
  558. if (lng.View.Scroll.isHorizontal(scroll)) {
  559. _resizeScrollContainerWidth(container, child);
  560. } else {
  561. _resizeScrollContainerHeight(scroll, container, child);
  562. }
  563. };
  564. /**
  565. * Resize all <article>s from determinated <section> based on a CSS property.
  566. *
  567. * @method article
  568. *
  569. * @param {object} Object reference of a determinated <section>
  570. * @param {string} Selector that refers to a section element
  571. * @param {string} CSS property
  572. * @param {string} Element reference for resizing
  573. */
  574. var article = function(section, selector, property, reference) {
  575. var element = section.children(selector);
  576. var ARTICLE = 'article';
  577. if (element.length > 0) {
  578. var reference_dimension = element[reference]();
  579. section.children(ARTICLE).css(property, reference_dimension + 'px');
  580. }
  581. };
  582. /**
  583. * Sets toolbars width, using total screen width
  584. *
  585. * @method toolbars
  586. */
  587. var toolbars = function() {
  588. var toolbar = '.toolbar nav';
  589. var all_toolbars = lng.Dom.query(toolbar);
  590. for (var i = 0, len = all_toolbars.length; i < len; i++) {
  591. var toolbar = lng.Dom.query(all_toolbars[i]);
  592. var toolbar_children = toolbar.children();
  593. var toolbar_children_width = (toolbar.width() / toolbar_children.length);
  594. toolbar_children.css('width', toolbar_children_width + 'px');
  595. }
  596. };
  597. var _resizeScrollContainerWidth = function(container, child) {
  598. var scroll_width = (container.children().length * child.width());
  599. container.css('width', scroll_width + 'px');
  600. };
  601. var _resizeScrollContainerHeight = function(scroll, container, child) {
  602. var total_children = container.children().length;
  603. var children_in_scroll_width = Math.floor(scroll.width() / child.width());
  604. var total_rows = Math.ceil(total_children / children_in_scroll_width);
  605. var scroll_height = (total_rows * child.height());
  606. container.css('height', scroll_height + 'px');
  607. };
  608. return {
  609. scroll: scroll,
  610. article: article,
  611. toolbars: toolbars
  612. };
  613. })(LUNGO);
  614. /**
  615. * Lungo Template system
  616. *
  617. * @namespace LUNGO.View
  618. * @class Template
  619. * @requires Zepto
  620. *
  621. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  622. * @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
  623. */
  624. LUNGO.View.Template = (function(lng, undefined) {
  625. var _templates = {};
  626. /**
  627. * Create a new databinding template based on a <markup>
  628. *
  629. * @method create
  630. *
  631. * @param {String} Id of the new databinding template
  632. * @param {String} <markup> of the new databinding template
  633. */
  634. var create = function(id, markup) {
  635. _templates[id] = markup;
  636. };
  637. /**
  638. * Returns the existence of a certain Id databinding template
  639. *
  640. * @method exists
  641. *
  642. * @param {String} Id of the databinding template
  643. * @return {Boolean} true if exists, false if not.
  644. */
  645. var exists = function(id) {
  646. return (_templates[id]) ? true : false;
  647. };
  648. /**
  649. * Returns the instance of a certain Id databinding template
  650. *
  651. * @method get
  652. *
  653. * @param {String} Id of the databinding template
  654. * @return {String} Markup of template
  655. */
  656. var get = function(id) {
  657. return _templates[id];
  658. };
  659. /**
  660. * Performs databinding process for a data set and a given template
  661. *
  662. * @method binding
  663. *
  664. * @param {String} Id of the container showing the result of databinding
  665. * @param {String} Databinding Template Id
  666. * @param {Object} Data for binding
  667. * @param {Function} Callback when the process is complete
  668. */
  669. var binding = function(container_id, template_id, data, callback) {
  670. lng.View.Template.Binding.create(container_id, template_id, data, callback);
  671. };
  672. return {
  673. create: create,
  674. exists: exists,
  675. get: get,
  676. binding: binding
  677. };
  678. })(LUNGO);
  679. /**
  680. * Lungo Data-Binding system
  681. *
  682. * @namespace LUNGO.View.Template
  683. * @class Binding
  684. * @requires Zepto
  685. *
  686. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  687. * @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
  688. */
  689. LUNGO.View.Template.Binding = (function(lng, undefined) {
  690. var BINDING_START = '{{';
  691. var BINDING_END = '}}';
  692. var BINDING_PARSER = /\{{.*?\}}/gi;
  693. /**
  694. * Performs databinding process for a data set and a given template
  695. *
  696. * @method create
  697. *
  698. * @param {String} Id of the container showing the result of databinding
  699. * @param {String} Databinding Template Id
  700. * @param {Object} Data for binding
  701. * @param {Function} Callback when the process is complete
  702. */
  703. var create = function(container_id, template_id, data, callback) {
  704. if (lng.View.Template.exists(template_id)) {
  705. var template = lng.View.Template.get(template_id);
  706. var markup = _processData(data, template);
  707. _render(container_id, markup);
  708. lng.Core.execute(callback);
  709. } else {
  710. lng.Core.log(3, 'lng.View.Template.binding: id ' + template_id + ' not exists');
  711. }
  712. };
  713. var dataAttribute = function(element, attribute) {
  714. var data = element.data(attribute.tag);
  715. if (data) {
  716. var html_binded = attribute.html.replace(BINDING_START + 'value' + BINDING_END, data);
  717. element.prepend(html_binded);
  718. }
  719. };
  720. var _processData = function(data, template) {
  721. var data_type = lng.Core.toType(data);
  722. if (data_type === 'array') {
  723. return _bindPropertiesInMultiplesElements(data, template);
  724. } else if (data_type === 'object') {
  725. return _bindProperties(data, template);
  726. } else {
  727. lng.Core.log(3, 'View.Template ERROR >> No type defined.');
  728. }
  729. };
  730. var _bindPropertiesInMultiplesElements = function(elements, template) {
  731. var markup = '';
  732. for (var i = 0, len = elements.length; i < len; i++) {
  733. markup += _bindProperties(elements[i], template);
  734. }
  735. return markup;
  736. };
  737. var _bindProperties = function(element, template) {
  738. var binding_field;
  739. for (var property in element) {
  740. if (lng.Core.isOwnProperty(element, property)) {
  741. binding_field = new RegExp(BINDING_START + property + BINDING_END, 'g');
  742. template = template.replace(binding_field, element[property]);
  743. }
  744. }
  745. return _removeNoBindedProperties(template);
  746. };
  747. var _removeNoBindedProperties = function(template) {
  748. return template.replace(BINDING_PARSER, '');
  749. };
  750. var _render = function(container_id, markup) {
  751. var container = lng.Dom.query('#' + container_id);
  752. container.html(markup);
  753. };
  754. return {
  755. create: create,
  756. dataAttribute: dataAttribute
  757. };
  758. })(LUNGO);
  759. /**
  760. * Auto generate lists based on Template and Data-Binding system
  761. *
  762. * @namespace LUNGO.View.Template
  763. * @class List
  764. * @requires Zepto
  765. *
  766. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  767. * @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
  768. */
  769. LUNGO.View.Template.List = (function(lng, undefined) {
  770. var _config = null;
  771. /**
  772. * Create a list based DataBind with a configuration object for an element <article>
  773. * if the config has a 'norecords' property it will display the norecords markup rather than nothing.
  774. *
  775. * @method create
  776. *
  777. * @param {object} Id of the container showing the result of databinding
  778. */
  779. var create = function(config) {
  780. _config = config;
  781. _config.container_id += '_list';
  782. if (_validateConfig()) {
  783. _order();
  784. // @ToDo >> _group();
  785. _render();
  786. _createScroll();
  787. }
  788. };
  789. var _validateConfig = function() {
  790. var checked = false;
  791. var container_exists = !! lng.Dom.query(_config.container_id);
  792. var template_exists = lng.View.Template.exists(_config.template_id);
  793. if (container_exists && template_exists) {
  794. //@ToDo >> Refactor to other method
  795. lng.Dom.query("#"+_config.container_id).html('');
  796. var type = lng.Core.toType(_config.data);
  797. if (type === 'array' || type === 'object') {
  798. checked = true;
  799. }
  800. }
  801. return checked;
  802. };
  803. var _order = function() {
  804. var order_field = _config.order_field;
  805. var order_type = (_config.order_type === 'desc') ? -1 : 1;
  806. if (order_field && order_type) {
  807. _config.data.sort(function(a, b) {
  808. return (a[order_field] < b[order_field]) ? - order_type :
  809. (a[order_field] > b[order_field]) ? order_type : 0;
  810. });
  811. }
  812. };
  813. // @ToDo >> group list by property
  814. var _group = function() {
  815. };
  816. var _render = function() {
  817. lng.View.Template.Binding.create(_config.container_id, _config.template_id, _config.data);
  818. };
  819. var _createScroll = function() {
  820. var container_id_for_scroll = lng.Dom.query('#' + _config.container_id).parent().attr('id');
  821. var list_config = { snap: 'li' };
  822. lng.View.Scroll.create(container_id_for_scroll, list_config);
  823. };
  824. return {
  825. create: create
  826. };
  827. })(LUNGO);
  828. /**
  829. * Wrapper of the third library iScroll
  830. *
  831. * @namespace LUNGO.View
  832. * @class Scroll
  833. * @requires Zepto
  834. * @requires iScroll
  835. *
  836. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  837. * @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
  838. */
  839. LUNGO.View.Scroll = (function(lng, undefined) {
  840. var DEFAULT_PROPERTIES = {
  841. hScroll: false,
  842. vScroll: false,
  843. useTransition: true,
  844. momentum: true,
  845. lockDirection: true,
  846. fixedScrollbar: true,
  847. fadeScrollbar: true,
  848. hideScrollbar: true
  849. };
  850. var HORIZONTAL_CLASS = 'horizontal';
  851. var CACHE_KEY = 'scrolls';
  852. var HEADER_FOOTER_BLEEDING = 90;
  853. /**
  854. * Creates a new iScroll element.
  855. *
  856. * @method create
  857. *
  858. * @param {string} Id of the container scroll.
  859. * @param {object} [OPTIONAL] Properties
  860. */
  861. var create = function(id, properties) {
  862. if (id) {
  863. var scroll = lng.Dom.query('#' + id);
  864. //ToDo >> Refactor
  865. setTimeout(function() {
  866. if (_needScroll(scroll)) {
  867. properties = _mixProperties(scroll, properties);
  868. _saveScrollInCache(id, properties);
  869. }
  870. }, 100);
  871. } else {
  872. lng.Core.log(3, 'ERROR: Impossible to create a <scroll> without ID');
  873. }
  874. };
  875. /**
  876. * Update iScroll element with new <markup> content.
  877. *
  878. * @method update
  879. *
  880. * @param {string} Id of the container scroll.
  881. * @param {string} Markup content
  882. */
  883. var update = function(id, content) {
  884. var scroll = lng.Dom.query('#' + id);
  885. var container = scroll.children().first();
  886. if (container.length === 0) {
  887. scroll.html('<div id="' + id + '_scrl"></div>');
  888. container = scroll.children().first();
  889. }
  890. container.html(content);
  891. lng.View.Resize.scroll(scroll);
  892. _refresh(id);
  893. };
  894. /**
  895. * Removes iScroll instance.
  896. *
  897. * @method remove
  898. *
  899. * @param {string} Id of the <section>
  900. */
  901. var remove = function(id) {
  902. if (lng.Data.Cache.exists(CACHE_KEY)) {
  903. lng.Data.Cache.get(CACHE_KEY, id).destroy();
  904. lng.Data.Cache.remove(CACHE_KEY, id);
  905. }
  906. };
  907. /**
  908. * Removes iScroll instance.
  909. *
  910. * @method scrollIsHorizontal
  911. *
  912. * @param {Object} Id of the <section>
  913. */
  914. var isHorizontal = function(scroll) {
  915. return (scroll.hasClass(HORIZONTAL_CLASS)) ? true : false;
  916. };
  917. var _needScroll = function(scroll) {
  918. var is_necessary = false;
  919. var element = scroll[0];
  920. if (element.clientHeight < element.scrollHeight) {
  921. is_necessary = true;
  922. var child_height = element.scrollHeight + HEADER_FOOTER_BLEEDING;
  923. _resizeChildContainer(element, child_height);
  924. }
  925. return is_necessary;
  926. };
  927. var _resizeChildContainer = function(element, height) {
  928. var child_container = lng.Dom.query(element).children().first();
  929. child_container.css('height', height + 'px');
  930. };
  931. var _saveScrollInCache = function(id, properties) {
  932. _createScrollIndexInCache();
  933. var scroll = lng.Data.Cache.get(CACHE_KEY);
  934. scroll[id] = new iScroll(id, properties);
  935. lng.Data.Cache.set(CACHE_KEY, scroll);
  936. };
  937. var _createScrollIndexInCache = function() {
  938. if (!lng.Data.Cache.exists(CACHE_KEY)) {
  939. lng.Data.Cache.set(CACHE_KEY, {});
  940. }
  941. }
  942. var _mixProperties = function(scroll, properties) {
  943. var scroll_type = isHorizontal(scroll) ? 'hScroll' : 'vScroll';
  944. properties || (properties = {});
  945. properties[scroll_type] = true;
  946. properties = lng.Core.mix(DEFAULT_PROPERTIES, properties);
  947. return properties;
  948. };
  949. var _refresh = function(id, properties) {
  950. !lng.Data.Cache.get(CACHE_KEY, id) && _saveScrollInCache(id);
  951. lng.Data.Cache.get(CACHE_KEY, id).refresh();
  952. };
  953. return {
  954. create: create,
  955. update: update,
  956. remove: remove,
  957. isHorizontal: isHorizontal
  958. };
  959. })(LUNGO);
  960. /**
  961. * Initialize the <articles> layout of a certain <section>
  962. *
  963. * @namespace LUNGO.View
  964. * @class Aside
  965. *
  966. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  967. * @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
  968. */
  969. LUNGO.View.Aside = (function(lng, undefined) {
  970. var toggle = function(section_id) {
  971. var articles = lng.Dom.query(section_id + ' article');
  972. articles.toggleClass('aside');
  973. };
  974. return {
  975. toggle: toggle
  976. };
  977. })(LUNGO);
  978. /**
  979. * Initialize the <articles> layout of a certain <section>
  980. *
  981. * @namespace LUNGO.View
  982. * @class Element
  983. *
  984. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  985. */
  986. LUNGO.View.Element = (function(lng, undefined) {
  987. var SELECTORS = {
  988. BUBBLE: '.bubble.count'
  989. };
  990. var BINDING_START = '{{';
  991. var BINDING_END = '}}';
  992. var count = function(selector, count) {
  993. var element = lng.Dom.query(selector);
  994. if (element ) {
  995. if (count > 0) {
  996. _setBubble (element, count);
  997. } else {
  998. element.children(SELECTORS.BUBBLE).remove();
  999. }
  1000. }
  1001. };
  1002. var _setBubble = function(element, count) {
  1003. var bubbles = element.children(SELECTORS.BUBBLE);
  1004. var total_bubbles = bubbles.length;
  1005. if (total_bubbles > 0) {
  1006. bubbles.html(count);
  1007. } else {
  1008. var count_html = LUNGO.Attributes.Data.Count.html;
  1009. var html_binded = count_html.replace(BINDING_START + 'value' + BINDING_END, count);
  1010. element.append(html_binded);
  1011. }
  1012. }
  1013. return {
  1014. count: count
  1015. };
  1016. })(LUNGO);
  1017. /**
  1018. * LungoJS Dom Handler
  1019. *
  1020. * @namespace LUNGO
  1021. * @class Dom
  1022. *
  1023. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  1024. * @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
  1025. */
  1026. LUNGO.Dom = (function(lng, $, undefined) {
  1027. /**
  1028. * Add an event listener
  1029. *
  1030. * @method query
  1031. *
  1032. * @param {string} <Markup> element selector
  1033. * @return {Object} Zepto <element> instance
  1034. */
  1035. var query = function(selector) {
  1036. return $(selector);
  1037. };
  1038. return {
  1039. query: query
  1040. };
  1041. })(LUNGO, Zepto);
  1042. /**
  1043. * Lungo DOM UI events Manager
  1044. *
  1045. * @namespace LUNGO.Dom
  1046. * @class Event
  1047. * @requires Zepto
  1048. *
  1049. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  1050. * @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
  1051. */
  1052. LUNGO.Dom.Event = (function(lng, undefined) {
  1053. /**
  1054. * Add an event listener
  1055. *
  1056. * @method bind
  1057. *
  1058. * @param {string} Selector that dispatches the event
  1059. * @param {string} Touch event name
  1060. * @param {Function} Callback function after the request
  1061. */
  1062. var bind = function(selector, event_name, callback) {
  1063. if (_isNotSpecialEvent(selector, event_name, callback)) {
  1064. lng.Dom.query(selector).bind(lng.Events.get(event_name), callback);
  1065. }
  1066. };
  1067. /**
  1068. * Remove bind event listener
  1069. *
  1070. * @method unbind
  1071. *
  1072. * @param {string} Selector that dispatches the event
  1073. * @param {string} Touch event name
  1074. */
  1075. var unbind = function(selector, event_name) {
  1076. lng.Dom.query(selector).unbind(lng.Events.get(event_name));
  1077. };
  1078. /**
  1079. * Add an event listener that listens to the selector for current and future elements
  1080. *
  1081. * @method live
  1082. *
  1083. * @param {string} Selector that dispatches the event
  1084. * @param {string} Touch event name
  1085. * @param {Function} Callback function after the request
  1086. */
  1087. var live = function(selector, event_name, callback) {
  1088. if (_isNotSpecialEvent(selector, event_name, callback)) {
  1089. lng.Dom.query(selector).live(lng.Events.get(event_name), callback);
  1090. }
  1091. };
  1092. /**
  1093. * Remove live listener
  1094. *
  1095. * @method die
  1096. *
  1097. * @param {string} Selector that dispatches the event
  1098. * @param {string} Event name
  1099. */
  1100. var die = function(selector, event_name) {
  1101. lng.Dom.query(selector).die(lng.Events.get(event_name));
  1102. };
  1103. /**
  1104. * Add an event listener without event delegation
  1105. *
  1106. * @method delegate
  1107. *
  1108. * @param {string} Selector that dispatches the event
  1109. * @param {string} Children of selector that dispatches the event
  1110. * @param {string} Touch event name
  1111. * @param {Function} Callback function after the request
  1112. */
  1113. var delegate = function(selector, children_selector, event_name, callback) {
  1114. if (_isNotSpecialEvent(selector, event_name, callback)) {
  1115. lng.Dom.query(selector).delegate(children_selector, lng.Events.get(event_name), callback);
  1116. }
  1117. };
  1118. /**
  1119. * Remove delegate event listener
  1120. *
  1121. * @method undelegate
  1122. *
  1123. * @param {string} Selector that dispatches the event
  1124. * @param {string} Children of selector that dispatches the event
  1125. */
  1126. var undelegate = function(selector, children_selector) {
  1127. lng.Dom.query(selector).undelegate(selector);
  1128. };
  1129. /**
  1130. * Listener for DOMelement
  1131. *
  1132. * @method listener
  1133. *
  1134. * @param {object} Selector that dispatches the event
  1135. * @param {string} Touch event name
  1136. * @param {Function} Callback function after the request
  1137. */
  1138. var listener = function(selector, event_name, callback) {
  1139. selector.addEventListener(lng.Events.get(event_name), function(event) {
  1140. setTimeout(callback, 0, event);
  1141. }, false);
  1142. };
  1143. var _isNotSpecialEvent = function(selector, event_name, callback) {
  1144. var is_special_event = false;
  1145. /*
  1146. var SPECIAL_EVENTS = {
  1147. SWIPE: 'swipe',
  1148. SWIPE_LEFT: 'swipeLeft',
  1149. SWIPE_RIGHT: 'swipeRight',
  1150. SWIPE_UP: 'swipeUp',
  1151. SWIPE_DOWN: 'swipeDown',
  1152. DOUBLE_TAP: 'doubleTap'
  1153. };
  1154. var special_event = SPECIAL_EVENTS[event_name];
  1155. lng.Dom.query(selector)[special_event](callback);
  1156. */
  1157. switch(event_name) {
  1158. case 'SWIPE':
  1159. lng.Dom.query(selector).swipe(callback);
  1160. break;
  1161. case 'SWIPE_LEFT':
  1162. lng.Dom.query(selector).swipeLeft(callback);
  1163. break;
  1164. case 'SWIPE_RIGHT':
  1165. lng.Dom.query(selector).swipeRight(callback);
  1166. break;
  1167. case 'SWIPE_UP':
  1168. lng.Dom.query(selector).swipeUp(callback);
  1169. break;
  1170. case 'SWIPE_DOWN':
  1171. lng.Dom.query(selector).swipeDown(callback);
  1172. break;
  1173. case 'DOUBLE_TAP':
  1174. if (lng.Environment.isDesktop()) {
  1175. lng.Dom.query(selector).live(lng.Events.get(event_name), callback);
  1176. } else {
  1177. lng.Dom.query(selector).doubleTap(callback);
  1178. }
  1179. break;
  1180. default:
  1181. is_special_event = true;
  1182. }
  1183. return is_special_event;
  1184. };
  1185. return {
  1186. bind: bind,
  1187. unbind: unbind,
  1188. live: live,
  1189. die: die,
  1190. delegate: delegate,
  1191. undelegate: undelegate,
  1192. listener: listener
  1193. };
  1194. })(LUNGO);
  1195. /**
  1196. * Object with data-attributes (HTML5) with a special <markup>
  1197. *
  1198. * @namespace LUNGO.Attributes
  1199. * @class Data
  1200. *
  1201. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  1202. * @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
  1203. */
  1204. LUNGO.Attributes.Data = {
  1205. Search: {
  1206. tag: 'search',
  1207. selector: '.list',
  1208. html: '<li class="search {{value}}"><input type="search" placeholder="Search..."><a href="#" class="button" data-icon="search"></a></li>'
  1209. },
  1210. Count: {
  1211. tag: 'count',
  1212. selector: '*',
  1213. html: '<span class="bubble count">{{value}}</span>'
  1214. },
  1215. Search: {
  1216. tag: 'search',
  1217. selector: '*',
  1218. html: '<input type="search" placeholder="{{value}}"/><a href="#" class="button" data-icon="search"></a>'
  1219. },
  1220. Icon: {
  1221. tag: 'icon',
  1222. selector: '*',
  1223. html: '<span class="icon {{value}}"></span>'
  1224. },
  1225. Image: {
  1226. tag: 'image',
  1227. selector: '*',
  1228. html: '<img src="{{value}}" class="icon" />'
  1229. },
  1230. Title: {
  1231. tag: 'title',
  1232. selector: 'header, footer, article',
  1233. html: '<h1 class="title">{{value}}</h1>'
  1234. },
  1235. Back: {
  1236. tag: 'back',
  1237. selector: 'header, footer',
  1238. html: '<a href="#back" data-target="section" class="back onleft button icon {{value}}"></a>'
  1239. }
  1240. };
  1241. /**
  1242. * Temporary cache system
  1243. *
  1244. * @namespace LUNGO.Data
  1245. * @class Cache
  1246. *
  1247. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  1248. * @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
  1249. */
  1250. LUNGO.Data.Cache = (function(lng, undefined) {
  1251. var _cache = {};
  1252. /**
  1253. * Sets in the LungoJS cache system a new key/value
  1254. *
  1255. * @method set
  1256. *
  1257. * @param {string} Key for the new value
  1258. * @param {object} Type of environment: DESKTOP_ENVIRONMENT or MOBILE_ENVIRONMENT
  1259. */
  1260. var set = function(key, value) {
  1261. if (exists(key)) {
  1262. _cache[key] = lng.Core.mix(get(key), value);
  1263. } else {
  1264. _cache[key] = value;
  1265. }
  1266. };
  1267. /**
  1268. * Returns the value of a given key.
  1269. *
  1270. * @method get
  1271. *
  1272. * @param {string} Key in LungoJS Cache System
  1273. * @param {string} [OPTIONAL] Subkey in LungoJS Cache System
  1274. * @return {object} Value
  1275. */
  1276. var get = function(key, value) {
  1277. if (arguments.length === 1) {
  1278. return _cache[key];
  1279. } else {
  1280. return _cache[arguments[0]][arguments[1]];
  1281. }
  1282. };
  1283. /**
  1284. * Removes the instance in LungoJs Cache System of a given key
  1285. *
  1286. * @method remove
  1287. *
  1288. * @param {string} Key in LungoJS Cache System
  1289. * @param {string} [OPTIONAL] Subkey in LungoJS Cache System
  1290. */
  1291. var remove = function(key, value) {
  1292. if (arguments.length === 1) {
  1293. delete _cache[key];
  1294. } else {
  1295. delete _cache[arguments[0]][arguments[1]];
  1296. }
  1297. };
  1298. /**
  1299. * Returns the existence of a key in LungoJs Cache System
  1300. *
  1301. * @method exists
  1302. *
  1303. * @param {String} Key in LungoJS Cache System
  1304. * @return {Boolean} true if exists, false if not
  1305. */
  1306. var exists = function(key) {
  1307. return (_cache[key]) ? true : false;
  1308. };
  1309. return {
  1310. set: set,
  1311. get: get,
  1312. remove: remove,
  1313. exists: exists
  1314. };
  1315. })(LUNGO);
  1316. /**
  1317. * Wrapper for using WebSql (HTML5 feature)
  1318. *
  1319. * @namespace LUNGO.Data
  1320. * @class Sql
  1321. *
  1322. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  1323. * @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
  1324. */
  1325. LUNGO.Data.Sql = (function(lng, undefined) {
  1326. var CONFIG = {
  1327. name: 'lungo_db',
  1328. version: '1.0',
  1329. size: 65536,
  1330. schema: []
  1331. };
  1332. var db = null;
  1333. /**
  1334. * Initialize the SQLite storage (HTML5 Feature)
  1335. *
  1336. * @method init
  1337. *
  1338. * @param {object} Configuration for the Database
  1339. */
  1340. var init = function(db_config) {
  1341. CONFIG = lng.Core.mix(CONFIG, db_config);
  1342. db = openDatabase(CONFIG.name, CONFIG.version, CONFIG.name, CONFIG.size);
  1343. if (db) {
  1344. _createSchema();
  1345. } else {
  1346. lng.Core.log(3, 'lng.Data.Sql >> Failed to connect to database.');
  1347. }
  1348. };
  1349. /**
  1350. * Select a data set of a given table and based on a selection object
  1351. *
  1352. * @method select
  1353. *
  1354. * @param {string} Name of the table in the database
  1355. * @param {object} [OPTIONAL] Object selection condition
  1356. * @param {Function} Callback when the process is complete
  1357. */
  1358. var select = function(table, where_obj, callback) {
  1359. var where = (where_obj) ? ' WHERE ' + _convertToSql(where_obj, 'AND') : '';
  1360. execute('SELECT * FROM ' + table + where, function(rs) {
  1361. var result = [];
  1362. for (var i = 0, len = rs.rows.length; i < len; i++) {
  1363. result.push(rs.rows.item(i));
  1364. }
  1365. _callbackResponse(callback, result);
  1366. });
  1367. };
  1368. /**
  1369. * Inserts a data set of a given table and based on a data object
  1370. *
  1371. * @method insert
  1372. *
  1373. * @param {string} Name of the table in the database
  1374. * @param {object} Data object to insert in table
  1375. */
  1376. var insert = function(table, data_obj, callback) {
  1377. var fields = '';
  1378. var values = '';
  1379. for (var field in data_obj) {
  1380. if (lng.Core.isOwnProperty(data_obj, field)) {
  1381. var value = data_obj[field];
  1382. fields += (fields) ? ', ' + field : field;
  1383. if (values) values += ', ';
  1384. values += (isNaN(value)) ? '"' + value + '"' : value;
  1385. }
  1386. }
  1387. execute('INSERT INTO ' + table + ' (' + fields + ') VALUES (' + values + ')');
  1388. };
  1389. /**
  1390. * Updates a data set of a given table and based on a data object and
  1391. * an optional selection object
  1392. *
  1393. * @method update
  1394. *
  1395. * @param {string} Name of the table in the database
  1396. * @param {object} Data object to update in table
  1397. * @param {object} [OPTIONAL] Object selection condition
  1398. */
  1399. var update = function(table, data_obj, where_obj, callback) {
  1400. var sql = 'UPDATE ' + table + ' SET ' + _convertToSql(data_obj, ',');
  1401. if (where_obj) sql += ' WHERE ' + _convertToSql(where_obj, 'AND');
  1402. execute(sql);
  1403. };
  1404. /**
  1405. * Delete a data set of a given table and based on a selection object
  1406. *
  1407. * @method drop
  1408. *
  1409. * @param {string} Name of the table in the database
  1410. * @param {object} [OPTIONAL] Object selection condition
  1411. */
  1412. var drop = function(table, where_obj, callback) {
  1413. var where = (where_obj) ? ' WHERE ' + _convertToSql(where_obj, 'AND') : '';
  1414. execute('DELETE FROM ' + table + where + ';');
  1415. };
  1416. /**
  1417. * Executes a SQL statement in the SQLite storage
  1418. *
  1419. * @method execute
  1420. *
  1421. * @param {string} SQL statement
  1422. * @param {Function} Callback when the process is complete
  1423. */
  1424. var execute = function(sql, callback) {
  1425. lng.Core.log(1, 'lng.Data.Sql >> ' + sql);
  1426. db.transaction(function(tx) {
  1427. tx.executeSql(sql, [], function(tx, rs) {
  1428. _callbackResponse(callback, rs);
  1429. }, _throwError);
  1430. });
  1431. };
  1432. var _createSchema = function() {
  1433. var schema = CONFIG.schema;
  1434. var schema_len = schema.length;
  1435. if (!schema_len) return;
  1436. for (var i = 0; i < schema_len; i++) {
  1437. var current = schema[i];
  1438. _regenerateTable(current);
  1439. _createTable(current.name, current.fields);
  1440. }
  1441. };
  1442. var _createTable = function(table, fields) {
  1443. var sql_fields = '';
  1444. for (var field in fields) {
  1445. if (lng.Core.isOwnProperty(fields, field)) {
  1446. if (sql_fields) sql_fields += ', ';
  1447. sql_fields += field + ' ' + fields[field];
  1448. }
  1449. }
  1450. execute('CREATE TABLE IF NOT EXISTS ' + table + ' (' + sql_fields + ');');
  1451. };
  1452. var _regenerateTable = function(table) {
  1453. if (table.drop === true) {
  1454. _dropTable(table.name);
  1455. }
  1456. };
  1457. var _dropTable = function(table) {
  1458. execute('DROP TABLE IF EXISTS ' + table);
  1459. };
  1460. var _convertToSql = function(fields, separator) {
  1461. var sql = '';
  1462. for (var field in fields) {
  1463. if (lng.Core.isOwnProperty(fields, field)) {
  1464. var value = fields[field];
  1465. if (sql) sql += ' ' + separator + ' ';
  1466. sql += field + '=';
  1467. sql += (isNaN(value)) ? '"' + value + '"' : value;
  1468. }
  1469. }
  1470. return sql;
  1471. };
  1472. var _callbackResponse = function(callback, response) {
  1473. if (lng.Core.toType(callback) === 'function') {
  1474. setTimeout(callback, 100, response);
  1475. }
  1476. };
  1477. var _throwError = function(transaction, error) {
  1478. lng.Core.log(3, 'lng.Data.Sql >> ' + error.code + ': ' + error.message);
  1479. };
  1480. return {
  1481. init: init,
  1482. select: select,
  1483. insert: insert,
  1484. update: update,
  1485. drop: drop,
  1486. execute: execute
  1487. };
  1488. })(LUNGO);
  1489. /**
  1490. * Wrapper for using LocalStorage & SessionStorage (HTML5 Feature)
  1491. *
  1492. * @namespace LUNGO.Data
  1493. * @class Storage
  1494. *
  1495. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  1496. * @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
  1497. */
  1498. LUNGO.Data.Storage = (function(lng, undefined) {
  1499. return {
  1500. };
  1501. })(LUNGO);
  1502. /**
  1503. * Boot for a new LungoJS Application instance
  1504. *
  1505. * @namespace LUNGO
  1506. * @class App
  1507. *
  1508. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  1509. * @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
  1510. */
  1511. LUNGO.Boot = (function(lng, undefined) {
  1512. return function() {
  1513. lng.Environment.start();
  1514. lng.Boot.Layout.start();
  1515. lng.Boot.Events.start();
  1516. lng.Boot.Data.start();
  1517. lng.Boot.Section.start();
  1518. lng.Boot.Article.start();
  1519. };
  1520. })(LUNGO);
  1521. /**
  1522. * Initialize the Layout of LungoJS (if it's a mobile environment)
  1523. *
  1524. * @namespace LUNGO.Boot
  1525. * @class Layout
  1526. *
  1527. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  1528. */
  1529. LUNGO.Boot.Layout = (function(lng, undefined) {
  1530. var _window = null;
  1531. var _document = null;
  1532. /**
  1533. * Initializes the automatic subscription events by markup of the project.
  1534. *
  1535. * @method init
  1536. *
  1537. */
  1538. var start = function() {
  1539. if (!lng.Environment.isDesktop()) {
  1540. _window = window;
  1541. _document = _window.document;
  1542. _resizeLayout();
  1543. }
  1544. };
  1545. var _resizeLayout = function() {
  1546. if (_window.innerHeight == 356) {
  1547. var _height = 416;
  1548. lng.Dom.query('body').css('height', _height + 'px');
  1549. _hideNavigationBar();
  1550. }
  1551. };
  1552. var _hideNavigationBar = function() {
  1553. if( !location.hash || !_window.addEventListener ){
  1554. _window.scrollTo( 0, 1 );
  1555. var scrollTop = 1,
  1556. //reset to 0 on bodyready, if needed
  1557. bodycheck = setInterval(function(){
  1558. if( _document.body ){
  1559. clearInterval( bodycheck );
  1560. scrollTop = 'scrollTop' in _document.body ? _document.body.scrollTop : 1;
  1561. _window.scrollTo( 0, scrollTop === 1 ? 0 : 1 );
  1562. }
  1563. }, 15 );
  1564. _window.addEventListener( 'load', function(){
  1565. setTimeout(function(){
  1566. _window.scrollTo( 0, scrollTop === 1 ? 0 : 1 );
  1567. }, 0);
  1568. }, false );
  1569. }
  1570. };
  1571. return {
  1572. start: start
  1573. };
  1574. })(LUNGO);
  1575. /**
  1576. * Initialize the <article> element
  1577. *
  1578. * @namespace LUNGO.Boot
  1579. * @class Article
  1580. * @requires Zepto
  1581. *
  1582. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  1583. * @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
  1584. */
  1585. LUNGO.Boot.Article = (function(lng, undefined) {
  1586. var SELECTORS = {
  1587. LIST_IN_ARTICLE: 'article.list',
  1588. SCROLL_IN_ARTICLE: '.scrollable',
  1589. CHECKBOX_IN_ARTICLE: '.checkbox, .radio'
  1590. };
  1591. /**
  1592. * Initializes the markup elements of an article
  1593. *
  1594. * @method init
  1595. */
  1596. var start = function() {
  1597. _initElement(SELECTORS.LIST_IN_ARTICLE, _createListElement);
  1598. _initElement(SELECTORS.SCROLL_IN_ARTICLE, _createScrollElement);
  1599. _initElement(SELECTORS.CHECKBOX_IN_ARTICLE, _createCheckboxElement);
  1600. };
  1601. var _initElement = function(selector, callback) {
  1602. var found_elements = lng.Dom.query(selector);
  1603. for (var i = 0, len = found_elements.length; i < len; i++) {
  1604. var element = lng.Dom.query(found_elements[i]);
  1605. lng.Core.execute(callback, element);
  1606. }
  1607. };
  1608. var _createListElement = function(article) {
  1609. if (article.children().length === 0) {
  1610. var article_id = article.attr('id');
  1611. article.append('<ul id="' + article_id + '_list"></ul>');
  1612. }
  1613. };
  1614. var _createScrollElement = function(scroll) {
  1615. var scroll_id = scroll.attr('id');
  1616. lng.View.Scroll.create(scroll_id);
  1617. };
  1618. var _createCheckboxElement = function(checkbox) {
  1619. checkbox.append('<span>&nbsp;</span>');
  1620. };
  1621. return {
  1622. start: start
  1623. };
  1624. })(LUNGO);
  1625. /**
  1626. * Make an analysis of Data attributes in HTML elements and creates a <markup>
  1627. * based on each data type.
  1628. *
  1629. * @namespace LUNGO.Boot
  1630. * @class Data
  1631. * @requires Zepto
  1632. *
  1633. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  1634. * @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
  1635. */
  1636. LUNGO.Boot.Data = (function(lng, undefined) {
  1637. /**
  1638. * Initialize the <markup> data-attributes analisys
  1639. *
  1640. * @method init
  1641. *
  1642. *
  1643. */
  1644. var start = function() {
  1645. var attributes = lng.Attributes.Data;
  1646. for (var attribute in attributes) {
  1647. if (lng.Core.isOwnProperty(attributes, attribute)) {
  1648. _findElements(attributes[attribute]);
  1649. }
  1650. }
  1651. };
  1652. var _findElements = function(attribute) {
  1653. var elements = lng.Dom.query(attribute.selector);
  1654. for (var i = 0, len = elements.length; i < len; i++) {
  1655. var element = lng.Dom.query(elements[i]);
  1656. lng.View.Template.Binding.dataAttribute(element, attribute);
  1657. }
  1658. };
  1659. return {
  1660. start: start
  1661. };
  1662. })(LUNGO);
  1663. /**
  1664. * Initialize the automatic DOM UI events
  1665. *
  1666. * @namespace LUNGO.Boot
  1667. * @class Events
  1668. *
  1669. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  1670. * @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
  1671. */
  1672. LUNGO.Boot.Events = (function(lng, undefined) {
  1673. /**
  1674. * Initializes the automatic subscription events by markup of the project.
  1675. *
  1676. * @method init
  1677. *
  1678. */
  1679. var start = function() {
  1680. var touch_move_event = 'TOUCH_MOVE';
  1681. var touch_start_event = 'TOUCH_START';
  1682. var tap = 'TAP';
  1683. var orientation_change = 'ORIENTATION_CHANGE';
  1684. var target_selector = 'a[href][data-target]';
  1685. var target_selector_from_aside = 'aside a[href][data-target]';
  1686. lng.Dom.Event.listener(document, touch_move_event, _iScroll);
  1687. lng.Dom.Event.listener(window, orientation_change, _changeOrientation);
  1688. lng.Dom.Event.live(target_selector_from_aside, touch_start_event, _toggleAside);
  1689. lng.Dom.Event.live(target_selector, tap, _loadTarget);
  1690. };
  1691. var _iScroll = function(event) {
  1692. event.preventDefault();
  1693. };
  1694. var _changeOrientation = function(event) {
  1695. lng.View.Resize.toolbars();
  1696. };
  1697. var _toggleAside = function(event) {
  1698. var link = lng.Dom.query(this);
  1699. var section_id = _getParentIdOfElement(link);
  1700. lng.View.Aside.toggle(section_id);
  1701. event.preventDefault();
  1702. };
  1703. var _loadTarget = function(event) {
  1704. var link = lng.Dom.query(this);
  1705. _selectTarget(link);
  1706. event.preventDefault();
  1707. };
  1708. var _selectTarget = function(link) {
  1709. var target_type = link.data('target');
  1710. switch(target_type) {
  1711. case 'section':
  1712. var target_id = link.attr('href');
  1713. _goSection(target_id);
  1714. break;
  1715. case 'article':
  1716. _goArticle(link);
  1717. break;
  1718. case 'aside':
  1719. _goAside(link);
  1720. break;
  1721. }
  1722. };
  1723. var _goSection = function(id) {
  1724. if (id === '#back') {
  1725. lng.Router.back();
  1726. } else {
  1727. lng.Router.section(id);
  1728. }
  1729. };
  1730. var _goArticle = function(element) {
  1731. var section_id = _getParentIdOfElement(element);
  1732. var article_id = element.attr('href');
  1733. lng.Router.article(section_id, article_id);
  1734. };
  1735. var _goAside = function(element) {
  1736. var section_id = _getParentIdOfElement(element);
  1737. lng.View.Aside.toggle(section_id);
  1738. };
  1739. var _getParentIdOfElement = function(element) {
  1740. var parent_id = '#' + element.parents('section').attr('id');
  1741. return parent_id;
  1742. };
  1743. return {
  1744. start: start
  1745. };
  1746. })(LUNGO);
  1747. /**
  1748. * Initialize the <section> element
  1749. *
  1750. * @namespace LUNGO.Boot
  1751. * @class Section
  1752. * @requires Zepto
  1753. *
  1754. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  1755. * @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
  1756. */
  1757. LUNGO.Boot.Section = (function(lng, undefined) {
  1758. var SELECTORS = {
  1759. ARTICLE: 'article',
  1760. SECTION: 'section'
  1761. };
  1762. var ACTIVE_CLASS = 'current';
  1763. /**
  1764. * Initializes all <section>s of the project
  1765. *
  1766. * @method init
  1767. */
  1768. var start = function() {
  1769. var sections = lng.Dom.query(SELECTORS.SECTION);
  1770. _initFirstSection(sections);
  1771. _initAllSections(sections);
  1772. _initAllAsides();
  1773. lng.View.Resize.toolbars();
  1774. };
  1775. var _initFirstSection = function(sections) {
  1776. var first_section = sections.first();
  1777. var first_section_id = '#' + first_section.attr('id');
  1778. first_section.addClass(ACTIVE_CLASS);
  1779. lng.Router.History.add(first_section_id);
  1780. };
  1781. var _initAllSections = function(sections) {
  1782. for (var i = 0, len = sections.length; i < len; i++) {
  1783. var section = lng.Dom.query(sections[i]);
  1784. _initFirstArticle(section);
  1785. }
  1786. };
  1787. var _initFirstArticle = function(section) {
  1788. section.children(SELECTORS.ARTICLE).first().addClass(ACTIVE_CLASS);
  1789. };
  1790. var _initAllAsides = function() {
  1791. lng.Dom.query('aside').addClass('show');
  1792. };
  1793. return {
  1794. start: start
  1795. };
  1796. })(LUNGO);