lungo-1.0.3.js 55 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078
  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.3
  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.3';
  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: 'click',
  284. TOUCH_MOVE: 'mousemove',
  285. TOUCH_END: 'mouseup',
  286. TAP: 'click',
  287. DOUBLE_TAP: 'dblclick',
  288. ORIENTATION_CHANGE: 'orientationchange'
  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. /**
  376. * Handles the <sections> and <articles> to show
  377. *
  378. * @namespace LUNGO
  379. * @class Router
  380. * @requires Zepto
  381. *
  382. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  383. * @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
  384. */
  385. LUNGO.Router = (function(lng, undefined) {
  386. var CSS_CLASSES = {
  387. SHOW: 'show',
  388. HIDE: 'hide'
  389. };
  390. /**
  391. * Navigate to a <section>.
  392. *
  393. * @method section
  394. *
  395. * @param {string} Id of the <section>
  396. */
  397. var section = function(section_id) {
  398. var section_id = (section_id.indexOf('#')) ? '#' + section_id : section_id;
  399. var target = 'section' + section_id;
  400. if (_existsTarget(target)) {
  401. lng.Dom.query(_getHistoryCurrent()).removeClass(CSS_CLASSES.SHOW).addClass(CSS_CLASSES.HIDE);
  402. lng.Dom.query(section_id).addClass(CSS_CLASSES.SHOW);
  403. lng.Router.History.add(section_id);
  404. }
  405. };
  406. /**
  407. * Displays the <article> in a particular <section>.
  408. *
  409. * @method article
  410. *
  411. * @param {string} <section> Id
  412. * @param {string} <article> Id
  413. */
  414. var article = function(section_id, article_id) {
  415. var target = section_id + ' article' + article_id;
  416. if (_existsTarget(target)) {
  417. lng.View.Article.show(section_id, article_id);
  418. }
  419. };
  420. /**
  421. * Return to previous section.
  422. *
  423. * @method back
  424. */
  425. var back = function() {
  426. lng.Dom.query(_getHistoryCurrent()).removeClass(CSS_CLASSES.SHOW);
  427. lng.Router.History.removeLast();
  428. lng.Dom.query(_getHistoryCurrent()).removeClass(CSS_CLASSES.HIDE).addClass(CSS_CLASSES.SHOW);
  429. };
  430. var _existsTarget = function(target) {
  431. var exists = false;
  432. if ($(target).length > 0) {
  433. exists = true;
  434. } else {
  435. lng.Core.log(3, 'Lungo.Router ERROR: The target ' + target + ' does not exists.');
  436. }
  437. return exists;
  438. }
  439. var _getHistoryCurrent = function() {
  440. return lng.Router.History.current();
  441. };
  442. return {
  443. section: section,
  444. article: article,
  445. back: back
  446. };
  447. })(LUNGO);
  448. /**
  449. * Stores the displayed <sections> as a historical.
  450. *
  451. * @namespace LUNGO.Router
  452. * @class History
  453. *
  454. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  455. * @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
  456. */
  457. LUNGO.Router.History = (function(undefined) {
  458. var _history = [];
  459. /**
  460. * Create a new element to the browsing history based on the current section id.
  461. *
  462. * @method add
  463. *
  464. * @param {string} Id of the section
  465. */
  466. var add = function(section_id) {
  467. if (section_id !== current()) {
  468. _history.push(section_id);
  469. }
  470. };
  471. /**
  472. * Returns the current browsing history section id.
  473. *
  474. * @method current
  475. *
  476. * @return {string} Current section id
  477. */
  478. var current = function() {
  479. return _history[_history.length - 1];
  480. };
  481. /**
  482. * Removes the current item browsing history.
  483. *
  484. * @method removeLast
  485. */
  486. var removeLast = function() {
  487. _history.length -= 1;
  488. };
  489. return {
  490. add: add,
  491. current: current,
  492. removeLast: removeLast
  493. };
  494. })();
  495. /**
  496. * Initialize the <articles> layout of a certain <section>
  497. *
  498. * @namespace LUNGO.View
  499. * @class Article
  500. *
  501. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  502. * @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
  503. */
  504. LUNGO.View.Article = (function(lng, undefined) {
  505. var SELECTORS = {
  506. ARTICLE: 'article',
  507. NAVIGATION_ITEM: 'a'
  508. };
  509. var CSS_CLASSES = {
  510. ACTIVE: 'current'
  511. };
  512. var show = function(section_id, article_id) {
  513. var nav_items = section_id + ' ' + SELECTORS.NAVIGATION_ITEM;
  514. _disableNavItems(nav_items);
  515. var current_nav_item = lng.Dom.query(nav_items + '[href="' + article_id + '"]');
  516. current_nav_item.addClass(CSS_CLASSES.ACTIVE);
  517. _setTitle(section_id, current_nav_item);
  518. _showContainer(section_id, article_id);
  519. };
  520. var _disableNavItems = function(items) {
  521. lng.Dom.query(items).removeClass(CSS_CLASSES.ACTIVE);
  522. };
  523. var _showContainer = function(section_id, article_id) {
  524. var section_articles = section_id + ' ' + SELECTORS.ARTICLE;
  525. lng.Dom.query(section_articles).removeClass(CSS_CLASSES.ACTIVE);
  526. lng.Dom.query(article_id).addClass(CSS_CLASSES.ACTIVE);
  527. };
  528. var _setTitle = function(id, item) {
  529. var title = item.data('title');
  530. if (title) {
  531. var section_title = id + ' header .title, ' + id + ' footer .title';
  532. lng.Dom.query(section_title).text(title);
  533. }
  534. };
  535. return {
  536. show: show
  537. };
  538. })(LUNGO);
  539. /**
  540. *
  541. *
  542. * @namespace LUNGO.View
  543. * @class Resize
  544. *
  545. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  546. * @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
  547. */
  548. LUNGO.View.Resize = (function(lng, undefined) {
  549. /**
  550. * Rezise a <scroll> element
  551. *
  552. * @method scroll
  553. *
  554. * @param {object} Object reference of a determinated <section>
  555. */
  556. var scroll = function(scroll) {
  557. var container = scroll.children().first();
  558. var child = container.children().first();
  559. if (lng.View.Scroll.isHorizontal(scroll)) {
  560. _resizeScrollContainerWidth(container, child);
  561. } else {
  562. _resizeScrollContainerHeight(scroll, container, child);
  563. }
  564. };
  565. /**
  566. * Resize all <article>s from determinated <section> based on a CSS property.
  567. *
  568. * @method article
  569. *
  570. * @param {object} Object reference of a determinated <section>
  571. * @param {string} Selector that refers to a section element
  572. * @param {string} CSS property
  573. * @param {string} Element reference for resizing
  574. */
  575. var article = function(section, selector, property, reference) {
  576. var element = section.children(selector);
  577. var ARTICLE = 'article';
  578. if (element.length > 0) {
  579. var reference_dimension = element[reference]();
  580. section.children(ARTICLE).css(property, reference_dimension + 'px');
  581. }
  582. };
  583. /**
  584. * Sets toolbars width, using total screen width
  585. *
  586. * @method toolbars
  587. */
  588. var toolbars = function() {
  589. var toolbar = '.toolbar nav';
  590. var all_toolbars = lng.Dom.query(toolbar);
  591. for (var i = 0, len = all_toolbars.length; i < len; i++) {
  592. var toolbar = lng.Dom.query(all_toolbars[i]);
  593. var toolbar_children = toolbar.children();
  594. var toolbar_children_width = (toolbar.width() / toolbar_children.length);
  595. toolbar_children.css('width', toolbar_children_width + 'px');
  596. }
  597. };
  598. var _resizeScrollContainerWidth = function(container, child) {
  599. var scroll_width = (container.children().length * child.width());
  600. container.css('width', scroll_width + 'px');
  601. };
  602. var _resizeScrollContainerHeight = function(scroll, container, child) {
  603. var total_children = container.children().length;
  604. var children_in_scroll_width = Math.floor(scroll.width() / child.width());
  605. var total_rows = Math.ceil(total_children / children_in_scroll_width);
  606. var scroll_height = (total_rows * child.height());
  607. container.css('height', scroll_height + 'px');
  608. };
  609. return {
  610. scroll: scroll,
  611. article: article,
  612. toolbars: toolbars
  613. };
  614. })(LUNGO);
  615. /**
  616. * Lungo Template system
  617. *
  618. * @namespace LUNGO.View
  619. * @class Template
  620. * @requires Zepto
  621. *
  622. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  623. * @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
  624. */
  625. LUNGO.View.Template = (function(lng, undefined) {
  626. var _templates = {};
  627. /**
  628. * Create a new databinding template based on a <markup>
  629. *
  630. * @method create
  631. *
  632. * @param {String} Id of the new databinding template
  633. * @param {String} <markup> of the new databinding template
  634. */
  635. var create = function(id, markup) {
  636. _templates[id] = markup;
  637. };
  638. /**
  639. * Returns the existence of a certain Id databinding template
  640. *
  641. * @method exists
  642. *
  643. * @param {String} Id of the databinding template
  644. * @return {Boolean} true if exists, false if not.
  645. */
  646. var exists = function(id) {
  647. return (_templates[id]) ? true : false;
  648. };
  649. /**
  650. * Returns the instance of a certain Id databinding template
  651. *
  652. * @method get
  653. *
  654. * @param {String} Id of the databinding template
  655. * @return {String} Markup of template
  656. */
  657. var get = function(id) {
  658. return _templates[id];
  659. };
  660. /**
  661. * Performs databinding process for a data set and a given template
  662. *
  663. * @method binding
  664. *
  665. * @param {String} Id of the container showing the result of databinding
  666. * @param {String} Databinding Template Id
  667. * @param {Object} Data for binding
  668. * @param {Function} Callback when the process is complete
  669. */
  670. var binding = function(container_id, template_id, data, callback) {
  671. lng.View.Template.Binding.create(container_id, template_id, data, callback);
  672. };
  673. return {
  674. create: create,
  675. exists: exists,
  676. get: get,
  677. binding: binding
  678. };
  679. })(LUNGO);
  680. /**
  681. * Lungo Data-Binding system
  682. *
  683. * @namespace LUNGO.View.Template
  684. * @class Binding
  685. * @requires Zepto
  686. *
  687. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  688. * @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
  689. */
  690. LUNGO.View.Template.Binding = (function(lng, undefined) {
  691. var BINDING_START = '{{';
  692. var BINDING_END = '}}';
  693. var BINDING_PARSER = /\{{.*?\}}/gi;
  694. /**
  695. * Performs databinding process for a data set and a given template
  696. *
  697. * @method create
  698. *
  699. * @param {String} Id of the container showing the result of databinding
  700. * @param {String} Databinding Template Id
  701. * @param {Object} Data for binding
  702. * @param {Function} Callback when the process is complete
  703. */
  704. var create = function(container_id, template_id, data, callback) {
  705. if (lng.View.Template.exists(template_id)) {
  706. var template = lng.View.Template.get(template_id);
  707. var markup = _processData(data, template);
  708. _render(container_id, markup);
  709. lng.Core.execute(callback);
  710. } else {
  711. lng.Core.log(3, 'lng.View.Template.binding: id ' + template_id + ' not exists');
  712. }
  713. };
  714. var dataAttribute = function(element, attribute) {
  715. var data = element.data(attribute.tag);
  716. if (data) {
  717. var html_binded = attribute.html.replace(BINDING_START + 'value' + BINDING_END, data);
  718. element.prepend(html_binded);
  719. }
  720. };
  721. var _processData = function(data, template) {
  722. var data_type = lng.Core.toType(data);
  723. if (data_type === 'array') {
  724. return _bindPropertiesInMultiplesElements(data, template);
  725. } else if (data_type === 'object') {
  726. return _bindProperties(data, template);
  727. } else {
  728. lng.Core.log(3, 'View.Template ERROR >> No type defined.');
  729. }
  730. };
  731. var _bindPropertiesInMultiplesElements = function(elements, template) {
  732. var markup = '';
  733. for (var i = 0, len = elements.length; i < len; i++) {
  734. markup += _bindProperties(elements[i], template);
  735. }
  736. return markup;
  737. };
  738. var _bindProperties = function(element, template) {
  739. var binding_field;
  740. for (var property in element) {
  741. if (lng.Core.isOwnProperty(element, property)) {
  742. binding_field = new RegExp(BINDING_START + property + BINDING_END, 'g');
  743. template = template.replace(binding_field, element[property]);
  744. }
  745. }
  746. return _removeNoBindedProperties(template);
  747. };
  748. var _removeNoBindedProperties = function(template) {
  749. return template.replace(BINDING_PARSER, '');
  750. };
  751. var _render = function(container_id, markup) {
  752. var container = lng.Dom.query('#' + container_id);
  753. container.html(markup);
  754. };
  755. return {
  756. create: create,
  757. dataAttribute: dataAttribute
  758. };
  759. })(LUNGO);
  760. /**
  761. * Auto generate lists based on Template and Data-Binding system
  762. *
  763. * @namespace LUNGO.View.Template
  764. * @class List
  765. * @requires Zepto
  766. *
  767. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  768. * @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
  769. */
  770. LUNGO.View.Template.List = (function(lng, undefined) {
  771. var _config = null;
  772. /**
  773. * Create a list based DataBind with a configuration object for an element <article>
  774. * if the config has a 'norecords' property it will display the norecords markup rather than nothing.
  775. *
  776. * @method create
  777. *
  778. * @param {object} Id of the container showing the result of databinding
  779. */
  780. var create = function(config) {
  781. _config = config;
  782. _config.container_id += '_list';
  783. if (_validateConfig()) {
  784. _order();
  785. // @ToDo >> _group();
  786. _render();
  787. _createScroll();
  788. }
  789. };
  790. var _validateConfig = function() {
  791. var checked = false;
  792. var container_exists = !! lng.Dom.query(_config.container_id);
  793. var template_exists = lng.View.Template.exists(_config.template_id);
  794. if (container_exists && template_exists) {
  795. //@ToDo >> Refactor to other method
  796. lng.Dom.query("#"+_config.container_id).html('');
  797. var type = lng.Core.toType(_config.data);
  798. if (type === 'array' || type === 'object') {
  799. checked = true;
  800. }
  801. }
  802. return checked;
  803. };
  804. var _order = function() {
  805. var order_field = _config.order_field;
  806. var order_type = (_config.order_type === 'desc') ? -1 : 1;
  807. if (order_field && order_type) {
  808. _config.data.sort(function(a, b) {
  809. return (a[order_field] < b[order_field]) ? - order_type :
  810. (a[order_field] > b[order_field]) ? order_type : 0;
  811. });
  812. }
  813. };
  814. // @ToDo >> group list by property
  815. var _group = function() {
  816. };
  817. var _render = function() {
  818. lng.View.Template.Binding.create(_config.container_id, _config.template_id, _config.data);
  819. };
  820. var _createScroll = function() {
  821. var container_id_for_scroll = lng.Dom.query('#' + _config.container_id).parent().attr('id');
  822. var list_config = {snap:'li'};
  823. lng.View.Scroll.create(container_id_for_scroll, list_config);
  824. };
  825. return {
  826. create: create
  827. };
  828. })(LUNGO);
  829. /**
  830. * Wrapper of the third library iScroll
  831. *
  832. * @namespace LUNGO.View
  833. * @class Scroll
  834. * @requires Zepto
  835. * @requires iScroll
  836. *
  837. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  838. * @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
  839. */
  840. LUNGO.View.Scroll = (function(lng, undefined) {
  841. var DEFAULT_PROPERTIES = {
  842. hScroll: false,
  843. vScroll: false,
  844. useTransition: true,
  845. momentum: true,
  846. lockDirection: true,
  847. fixedScrollbar: true,
  848. fadeScrollbar: true,
  849. hideScrollbar: true
  850. };
  851. var HORIZONTAL_CLASS = 'horizontal';
  852. var CACHE_KEY = 'scrolls';
  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. var scroll_children = scroll.children();
  865. var need_scroll = (scroll_children.height() >= scroll.height());
  866. if (scroll_children.length > 0 && need_scroll) {
  867. properties = _mixProperties(scroll, properties);
  868. _saveScrollInCache(id, properties);
  869. }
  870. } else {
  871. lng.Core.log(3, 'ERROR: Impossible to create a <scroll> without ID');
  872. }
  873. };
  874. /**
  875. * Update iScroll element with new <markup> content.
  876. *
  877. * @method update
  878. *
  879. * @param {string} Id of the container scroll.
  880. * @param {string} Markup content
  881. */
  882. var update = function(id, content) {
  883. var scroll = lng.Dom.query('#' + id);
  884. var container = scroll.children().first();
  885. if (container.length === 0) {
  886. scroll.html('<div id="' + id + '_scrl"></div>');
  887. container = scroll.children().first();
  888. }
  889. container.html(content);
  890. lng.View.Resize.scroll(scroll);
  891. _refresh(id);
  892. };
  893. /**
  894. * Removes iScroll instance.
  895. *
  896. * @method remove
  897. *
  898. * @param {string} Id of the <section>
  899. */
  900. var remove = function(id) {
  901. if (lng.Data.Cache.exists(CACHE_KEY)) {
  902. lng.Data.Cache.get(CACHE_KEY, id).destroy();
  903. lng.Data.Cache.remove(CACHE_KEY, id);
  904. }
  905. };
  906. /**
  907. * Removes iScroll instance.
  908. *
  909. * @method scrollIsHorizontal
  910. *
  911. * @param {Object} Id of the <section>
  912. */
  913. var isHorizontal = function(scroll) {
  914. return (scroll.hasClass(HORIZONTAL_CLASS)) ? true : false;
  915. };
  916. var _saveScrollInCache = function(id, properties) {
  917. _createScrollIndexInCache();
  918. var scroll = lng.Data.Cache.get(CACHE_KEY);
  919. scroll[id] = new iScroll(id, properties);
  920. lng.Data.Cache.set(CACHE_KEY, scroll);
  921. };
  922. var _createScrollIndexInCache = function() {
  923. if (!lng.Data.Cache.exists(CACHE_KEY)) {
  924. lng.Data.Cache.set(CACHE_KEY, {});
  925. }
  926. }
  927. var _mixProperties = function(scroll, properties) {
  928. var scroll_type = isHorizontal(scroll) ? 'hScroll' : 'vScroll';
  929. properties || (properties = {});
  930. properties[scroll_type] = true;
  931. properties = lng.Core.mix(DEFAULT_PROPERTIES, properties);
  932. return properties;
  933. };
  934. var _refresh = function(id, properties) {
  935. !lng.Data.Cache.get(CACHE_KEY, id) && _saveScrollInCache(id);
  936. lng.Data.Cache.get(CACHE_KEY, id).refresh();
  937. };
  938. return {
  939. create: create,
  940. update: update,
  941. remove: remove,
  942. isHorizontal: isHorizontal
  943. };
  944. })(LUNGO);
  945. /**
  946. * Initialize the <articles> layout of a certain <section>
  947. *
  948. * @namespace LUNGO.View
  949. * @class Article
  950. *
  951. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  952. * @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
  953. */
  954. LUNGO.View.Aside = (function(lng, undefined) {
  955. var toggle = function(section_id) {
  956. if (_isVisible(section_id)) {
  957. _hide(section_id);
  958. } else {
  959. _show(section_id);
  960. }
  961. };
  962. var _show = function(section_id) {
  963. lng.Dom.query(section_id + ' aside').addClass('show');
  964. var articles = lng.Dom.query(section_id + ' article');
  965. articles.toggleClass('aside');
  966. };
  967. var _hide = function(section_id) {
  968. var articles = lng.Dom.query(section_id + ' article');
  969. articles.toggleClass('aside');
  970. };
  971. var _isVisible = function(section_id) {
  972. var isVisible = lng.Dom.query(section_id + ' aside').hasClass('show');
  973. return isVisible;
  974. };
  975. return {
  976. toggle: toggle
  977. };
  978. })(LUNGO);/**
  979. * LungoJS Dom Handler
  980. *
  981. * @namespace LUNGO
  982. * @class Dom
  983. *
  984. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  985. * @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
  986. */
  987. LUNGO.Dom = (function(lng, $, undefined) {
  988. /**
  989. * Add an event listener
  990. *
  991. * @method query
  992. *
  993. * @param {string} <Markup> element selector
  994. * @return {Object} Zepto <element> instance
  995. */
  996. var query = function(selector) {
  997. return $(selector);
  998. };
  999. return {
  1000. query: query
  1001. };
  1002. })(LUNGO, Zepto);/**
  1003. * Lungo DOM UI events Manager
  1004. *
  1005. * @namespace LUNGO.Dom
  1006. * @class Event
  1007. * @requires Zepto
  1008. *
  1009. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  1010. * @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
  1011. */
  1012. LUNGO.Dom.Event = (function(lng, undefined) {
  1013. /**
  1014. * Add an event listener
  1015. *
  1016. * @method bind
  1017. *
  1018. * @param {string} Selector that dispatches the event
  1019. * @param {string} Touch event name
  1020. * @param {Function} Callback function after the request
  1021. */
  1022. var bind = function(selector, event_name, callback) {
  1023. if (_isNotSpecialEvent(selector, event_name, callback)) {
  1024. lng.Dom.query(selector).bind(lng.Events.get(event_name), callback);
  1025. }
  1026. };
  1027. /**
  1028. * Remove bind event listener
  1029. *
  1030. * @method unbind
  1031. *
  1032. * @param {string} Selector that dispatches the event
  1033. * @param {string} Touch event name
  1034. */
  1035. var unbind = function(selector, event_name) {
  1036. lng.Dom.query(selector).unbind(lng.Events.get(event_name));
  1037. };
  1038. /**
  1039. * Add an event listener that listens to the selector for current and future elements
  1040. *
  1041. * @method live
  1042. *
  1043. * @param {string} Selector that dispatches the event
  1044. * @param {string} Touch event name
  1045. * @param {Function} Callback function after the request
  1046. */
  1047. var live = function(selector, event_name, callback) {
  1048. if (_isNotSpecialEvent(selector, event_name, callback)) {
  1049. lng.Dom.query(selector).live(lng.Events.get(event_name), callback);
  1050. }
  1051. };
  1052. /**
  1053. * Remove live listener
  1054. *
  1055. * @method die
  1056. *
  1057. * @param {string} Selector that dispatches the event
  1058. * @param {string} Event name
  1059. */
  1060. var die = function(selector, event_name) {
  1061. lng.Dom.query(selector).die(lng.Events.get(event_name));
  1062. };
  1063. /**
  1064. * Add an event listener without event delegation
  1065. *
  1066. * @method delegate
  1067. *
  1068. * @param {string} Selector that dispatches the event
  1069. * @param {string} Children of selector that dispatches the event
  1070. * @param {string} Touch event name
  1071. * @param {Function} Callback function after the request
  1072. */
  1073. var delegate = function(selector, children_selector, event_name, callback) {
  1074. if (_isNotSpecialEvent(selector, event_name, callback)) {
  1075. lng.Dom.query(selector).delegate(children_selector, lng.Events.get(event_name), callback);
  1076. }
  1077. };
  1078. /**
  1079. * Remove delegate event listener
  1080. *
  1081. * @method undelegate
  1082. *
  1083. * @param {string} Selector that dispatches the event
  1084. * @param {string} Children of selector that dispatches the event
  1085. */
  1086. var undelegate = function(selector, children_selector) {
  1087. lng.Dom.query(selector).undelegate(selector);
  1088. };
  1089. /**
  1090. * Listener for DOMelement
  1091. *
  1092. * @method listener
  1093. *
  1094. * @param {object} Selector that dispatches the event
  1095. * @param {string} Touch event name
  1096. * @param {Function} Callback function after the request
  1097. */
  1098. var listener = function(selector, event_name, callback) {
  1099. selector.addEventListener(lng.Events.get(event_name), function(event) {
  1100. setTimeout(callback, 0, event);
  1101. }, false);
  1102. };
  1103. var _isNotSpecialEvent = function(selector, event_name, callback) {
  1104. var is_special_event = false;
  1105. /*
  1106. var SPECIAL_EVENTS = {
  1107. SWIPE: 'swipe',
  1108. SWIPE_LEFT: 'swipeLeft',
  1109. SWIPE_RIGHT: 'swipeRight',
  1110. SWIPE_UP: 'swipeUp',
  1111. SWIPE_DOWN: 'swipeDown',
  1112. DOUBLE_TAP: 'doubleTap'
  1113. };
  1114. var special_event = SPECIAL_EVENTS[event_name];
  1115. lng.Dom.query(selector)[special_event](callback);
  1116. */
  1117. switch(event_name) {
  1118. case 'SWIPE':
  1119. lng.Dom.query(selector).swipe(callback);
  1120. break;
  1121. case 'SWIPE_LEFT':
  1122. lng.Dom.query(selector).swipeLeft(callback);
  1123. break;
  1124. case 'SWIPE_RIGHT':
  1125. lng.Dom.query(selector).swipeRight(callback);
  1126. break;
  1127. case 'SWIPE_UP':
  1128. lng.Dom.query(selector).swipeUp(callback);
  1129. break;
  1130. case 'SWIPE_DOWN':
  1131. lng.Dom.query(selector).swipeDown(callback);
  1132. break;
  1133. case 'DOUBLE_TAP':
  1134. if (lng.Environment.isDesktop()) {
  1135. lng.Dom.query(selector).live(lng.Events.get(event_name), callback);
  1136. } else {
  1137. lng.Dom.query(selector).doubleTap(callback);
  1138. }
  1139. break;
  1140. default:
  1141. is_special_event = true;
  1142. }
  1143. return is_special_event;
  1144. };
  1145. return {
  1146. bind: bind,
  1147. unbind: unbind,
  1148. live: live,
  1149. die: die,
  1150. delegate: delegate,
  1151. undelegate: undelegate,
  1152. listener: listener
  1153. };
  1154. })(LUNGO);
  1155. /**
  1156. * Object with data-attributes (HTML5) with a special <markup>
  1157. *
  1158. * @namespace LUNGO.Attributes
  1159. * @class Data
  1160. *
  1161. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  1162. * @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
  1163. */
  1164. LUNGO.Attributes.Data = {
  1165. search: {
  1166. tag: 'search',
  1167. selector: '.list',
  1168. html: '<li class="search {{value}}"><input type="search" placeholder="Search..."><a href="#" class="button" data-icon="search"></a></li>'
  1169. },
  1170. icon: {
  1171. tag: 'icon',
  1172. selector: '*',
  1173. html: '<span class="icon {{value}}"></span>'
  1174. },
  1175. title: {
  1176. tag: 'title',
  1177. selector: 'header, footer',
  1178. html: '<h1 class="title">{{value}}</h1>'
  1179. },
  1180. back: {
  1181. tag: 'back',
  1182. selector: 'header, footer',
  1183. html: '<a href="#back" data-target="section" class="back onleft button icon {{value}}"></a>'
  1184. }
  1185. }; /**
  1186. * Make an analysis of <elements> in a <section>.
  1187. *
  1188. * @namespace LUNGO.Attributes
  1189. * @class Section
  1190. *
  1191. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  1192. * @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
  1193. */
  1194. LUNGO.Attributes.Section = {
  1195. header: {
  1196. name: 'header',
  1197. reference: 'height',
  1198. bind: 'top'
  1199. },
  1200. footer: {
  1201. name: 'footer',
  1202. reference: 'height',
  1203. bind: 'bottom'
  1204. }
  1205. };/**
  1206. * Temporary cache system
  1207. *
  1208. * @namespace LUNGO.Data
  1209. * @class Cache
  1210. *
  1211. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  1212. * @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
  1213. */
  1214. LUNGO.Data.Cache = (function(lng, undefined) {
  1215. var _cache = {};
  1216. /**
  1217. * Sets in the LungoJS cache system a new key/value
  1218. *
  1219. * @method set
  1220. *
  1221. * @param {string} Key for the new value
  1222. * @param {object} Type of environment: DESKTOP_ENVIRONMENT or MOBILE_ENVIRONMENT
  1223. */
  1224. var set = function(key, value) {
  1225. if (exists(key)) {
  1226. _cache[key] = lng.Core.mix(get(key), value);
  1227. } else {
  1228. _cache[key] = value;
  1229. }
  1230. };
  1231. /**
  1232. * Returns the value of a given key.
  1233. *
  1234. * @method get
  1235. *
  1236. * @param {string} Key in LungoJS Cache System
  1237. * @param {string} [OPTIONAL] Subkey in LungoJS Cache System
  1238. * @return {object} Value
  1239. */
  1240. var get = function(key, value) {
  1241. if (arguments.length === 1) {
  1242. return _cache[key];
  1243. } else {
  1244. return _cache[arguments[0]][arguments[1]];
  1245. }
  1246. };
  1247. /**
  1248. * Removes the instance in LungoJs Cache System of a given key
  1249. *
  1250. * @method remove
  1251. *
  1252. * @param {string} Key in LungoJS Cache System
  1253. * @param {string} [OPTIONAL] Subkey in LungoJS Cache System
  1254. */
  1255. var remove = function(key, value) {
  1256. if (arguments.length === 1) {
  1257. delete _cache[key];
  1258. } else {
  1259. delete _cache[arguments[0]][arguments[1]];
  1260. }
  1261. };
  1262. /**
  1263. * Returns the existence of a key in LungoJs Cache System
  1264. *
  1265. * @method exists
  1266. *
  1267. * @param {String} Key in LungoJS Cache System
  1268. * @return {Boolean} true if exists, false if not
  1269. */
  1270. var exists = function(key) {
  1271. return (_cache[key]) ? true : false;
  1272. };
  1273. return {
  1274. set: set,
  1275. get: get,
  1276. remove: remove,
  1277. exists: exists
  1278. };
  1279. })(LUNGO);/**
  1280. * Wrapper for using WebSql (HTML5 feature)
  1281. *
  1282. * @namespace LUNGO.Data
  1283. * @class Sql
  1284. *
  1285. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  1286. * @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
  1287. */
  1288. LUNGO.Data.Sql = (function(lng, undefined) {
  1289. var CONFIG = {
  1290. name: 'lungo_db',
  1291. version: '1.0',
  1292. size: 65536,
  1293. schema: []
  1294. };
  1295. var db = null;
  1296. /**
  1297. * Initialize the SQLite storage (HTML5 Feature)
  1298. *
  1299. * @method init
  1300. *
  1301. * @param {object} Configuration for the Database
  1302. */
  1303. var init = function(db_config) {
  1304. CONFIG = lng.Core.mix(CONFIG, db_config);
  1305. db = openDatabase(CONFIG.name, CONFIG.version, CONFIG.name, CONFIG.size);
  1306. if (db) {
  1307. _createSchema();
  1308. } else {
  1309. lng.Core.log(3, 'lng.Data.Sql >> Failed to connect to database.');
  1310. }
  1311. };
  1312. /**
  1313. * Select a data set of a given table and based on a selection object
  1314. *
  1315. * @method select
  1316. *
  1317. * @param {string} Name of the table in the database
  1318. * @param {object} [OPTIONAL] Object selection condition
  1319. * @param {Function} Callback when the process is complete
  1320. */
  1321. var select = function(table, where_obj, callback) {
  1322. var where = (where_obj) ? ' WHERE ' + _convertToSql(where_obj, 'AND') : '';
  1323. execute('SELECT * FROM ' + table + where, function(rs) {
  1324. var result = [];
  1325. for (var i = 0, len = rs.rows.length; i < len; i++) {
  1326. result.push(rs.rows.item(i));
  1327. }
  1328. if (result.length === 1) result = result[0];
  1329. _callbackResponse(callback, result);
  1330. });
  1331. };
  1332. /**
  1333. * Inserts a data set of a given table and based on a data object
  1334. *
  1335. * @method insert
  1336. *
  1337. * @param {string} Name of the table in the database
  1338. * @param {object} Data object to insert in table
  1339. */
  1340. var insert = function(table, data_obj) {
  1341. var fields = '';
  1342. var values = '';
  1343. for (var field in data_obj) {
  1344. if (lng.Core.isOwnProperty(data_obj, field)) {
  1345. var value = data_obj[field];
  1346. fields += (fields) ? ', ' + field : field;
  1347. if (values) values += ', ';
  1348. values += (isNaN(value)) ? '"' + value + '"' : value;
  1349. }
  1350. }
  1351. execute('INSERT INTO ' + table + ' (' + fields + ') VALUES (' + values + ')');
  1352. };
  1353. /**
  1354. * Updates a data set of a given table and based on a data object and
  1355. * an optional selection object
  1356. *
  1357. * @method update
  1358. *
  1359. * @param {string} Name of the table in the database
  1360. * @param {object} Data object to update in table
  1361. * @param {object} [OPTIONAL] Object selection condition
  1362. */
  1363. var update = function(table, data_obj, where_obj) {
  1364. var sql = 'UPDATE ' + table + ' SET ' + _convertToSql(data_obj, ',');
  1365. if (where_obj) sql += ' WHERE ' + _convertToSql(where_obj, 'AND');
  1366. execute(sql);
  1367. };
  1368. /**
  1369. * Delete a data set of a given table and based on a selection object
  1370. *
  1371. * @method drop
  1372. *
  1373. * @param {string} Name of the table in the database
  1374. * @param {object} [OPTIONAL] Object selection condition
  1375. */
  1376. var drop = function(table, where_obj) {
  1377. var where = (where_obj) ? ' WHERE ' + _convertToSql(where_obj, 'AND') : '';
  1378. execute('DELETE FROM ' + table + where + ';');
  1379. };
  1380. /**
  1381. * Executes a SQL statement in the SQLite storage
  1382. *
  1383. * @method execute
  1384. *
  1385. * @param {string} SQL statement
  1386. * @param {Function} Callback when the process is complete
  1387. */
  1388. var execute = function(sql, callback) {
  1389. lng.Core.log(1, 'lng.Data.Sql >> ' + sql);
  1390. db.transaction(function(tx) {
  1391. tx.executeSql(sql, [], function(tx, rs) {
  1392. _callbackResponse(callback, rs);
  1393. }, _throwError);
  1394. });
  1395. };
  1396. var _createSchema = function() {
  1397. var schema = CONFIG.schema;
  1398. var schema_len = schema.length;
  1399. if (!schema_len) return;
  1400. for (var i = 0; i < schema_len; i++) {
  1401. var current = schema[i];
  1402. _regenerateTable(current);
  1403. _createTable(current.name, current.fields);
  1404. }
  1405. };
  1406. var _createTable = function(table, fields) {
  1407. var sql_fields = '';
  1408. for (var field in fields) {
  1409. if (lng.Core.isOwnProperty(fields, field)) {
  1410. if (sql_fields) sql_fields += ', ';
  1411. sql_fields += field + ' ' + fields[field];
  1412. }
  1413. }
  1414. execute('CREATE TABLE IF NOT EXISTS ' + table + ' (' + sql_fields + ');');
  1415. };
  1416. var _regenerateTable = function(table) {
  1417. if (table.drop === true) {
  1418. _dropTable(table.name);
  1419. }
  1420. };
  1421. var _dropTable = function(table) {
  1422. execute('DROP TABLE IF EXISTS ' + table);
  1423. };
  1424. var _convertToSql = function(fields, separator) {
  1425. var sql = '';
  1426. for (var field in fields) {
  1427. if (lng.Core.isOwnProperty(fields, field)) {
  1428. var value = fields[field];
  1429. if (sql) sql += ' ' + separator + ' ';
  1430. sql += field + '=';
  1431. sql += (isNaN(value)) ? '"' + value + '"' : value;
  1432. }
  1433. }
  1434. return sql;
  1435. };
  1436. var _callbackResponse = function(callback, response) {
  1437. if (lng.Core.toType(callback) === 'function') {
  1438. setTimeout(callback, 100, response);
  1439. }
  1440. };
  1441. var _throwError = function(transaction, error) {
  1442. lng.Core.log(3, 'lng.Data.Sql >> ' + error.code + ': ' + error.message);
  1443. };
  1444. return {
  1445. init: init,
  1446. select: select,
  1447. insert: insert,
  1448. update: update,
  1449. drop: drop,
  1450. execute: execute
  1451. };
  1452. })(LUNGO);
  1453. /**
  1454. * Wrapper for using LocalStorage & SessionStorage (HTML5 Feature)
  1455. *
  1456. * @namespace LUNGO.Data
  1457. * @class Storage
  1458. *
  1459. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  1460. * @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
  1461. */
  1462. LUNGO.Data.Storage = (function(lng, undefined) {
  1463. return {
  1464. };
  1465. })(LUNGO);/**
  1466. * Boot for a new LungoJS Application instance
  1467. *
  1468. * @namespace LUNGO
  1469. * @class App
  1470. *
  1471. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  1472. * @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
  1473. */
  1474. LUNGO.Boot = (function(lng, undefined) {
  1475. return function() {
  1476. lng.Environment.start();
  1477. lng.Boot.Layout.start();
  1478. lng.Boot.Events.start();
  1479. lng.Boot.Data.start();
  1480. lng.Boot.Section.start();
  1481. lng.Boot.Article.start();
  1482. };
  1483. })(LUNGO);/**
  1484. * Initialize the Layout of LungoJS (if it's a mobile environment)
  1485. *
  1486. * @namespace LUNGO.Boot
  1487. * @class Layout
  1488. *
  1489. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  1490. */
  1491. LUNGO.Boot.Layout = (function(lng, undefined) {
  1492. var _window = null;
  1493. var _document = null;
  1494. /**
  1495. * Initializes the automatic subscription events by markup of the project.
  1496. *
  1497. * @method init
  1498. *
  1499. */
  1500. var start = function() {
  1501. if (!lng.Environment.isDesktop()) {
  1502. _window = window;
  1503. _document = _window.document;
  1504. _resizeLayout();
  1505. }
  1506. };
  1507. var _resizeLayout = function() {
  1508. if (_window.innerHeight == 356) {
  1509. var _height = 416;
  1510. lng.Dom.query('body').css('height', _height + 'px');
  1511. _hideNavigationBar();
  1512. }
  1513. };
  1514. var _hideNavigationBar = function() {
  1515. if( !location.hash || !_window.addEventListener ){
  1516. _window.scrollTo( 0, 1 );
  1517. var scrollTop = 1,
  1518. //reset to 0 on bodyready, if needed
  1519. bodycheck = setInterval(function(){
  1520. if( _document.body ){
  1521. clearInterval( bodycheck );
  1522. scrollTop = 'scrollTop' in _document.body ? _document.body.scrollTop : 1;
  1523. _window.scrollTo( 0, scrollTop === 1 ? 0 : 1 );
  1524. }
  1525. }, 15 );
  1526. _window.addEventListener( 'load', function(){
  1527. setTimeout(function(){
  1528. _window.scrollTo( 0, scrollTop === 1 ? 0 : 1 );
  1529. }, 0);
  1530. }, false );
  1531. }
  1532. };
  1533. return {
  1534. start: start
  1535. };
  1536. })(LUNGO);
  1537. /**
  1538. * Initialize the <article> element
  1539. *
  1540. * @namespace LUNGO.Boot
  1541. * @class Article
  1542. * @requires Zepto
  1543. *
  1544. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  1545. * @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
  1546. */
  1547. LUNGO.Boot.Article = (function(lng, undefined) {
  1548. var SELECTORS = {
  1549. LIST_IN_ARTICLE: 'article.list',
  1550. SCROLL_IN_ARTICLE: 'scroll',
  1551. CHECKBOX_IN_ARTICLE: '.checkbox, .radio'
  1552. };
  1553. /**
  1554. * Initializes the markup elements of an article
  1555. *
  1556. * @method init
  1557. */
  1558. var start = function() {
  1559. _initElement(SELECTORS.LIST_IN_ARTICLE, _createListElement);
  1560. _initElement(SELECTORS.SCROLL_IN_ARTICLE, _createScrollElement);
  1561. _initElement(SELECTORS.CHECKBOX_IN_ARTICLE, _createCheckboxElement);
  1562. };
  1563. var _initElement = function(selector, callback) {
  1564. var found_elements = lng.Dom.query(selector);
  1565. for (var i = 0, len = found_elements.length; i < len; i++) {
  1566. var element = lng.Dom.query(found_elements[i]);
  1567. lng.Core.execute(callback, element);
  1568. }
  1569. };
  1570. var _createListElement = function(article) {
  1571. if (article.children().length === 0) {
  1572. var article_id = article.attr('id');
  1573. article.append('<ul id="' + article_id + '_list"></ul>');
  1574. }
  1575. };
  1576. var _createScrollElement = function(scroll) {
  1577. var scroll_id = scroll.attr('id');
  1578. lng.View.Scroll.create(scroll_id);
  1579. };
  1580. var _createCheckboxElement = function(checkbox) {
  1581. checkbox.append('<span>&nbsp;</span>');
  1582. };
  1583. return {
  1584. start: start
  1585. };
  1586. })(LUNGO);
  1587. /**
  1588. * Make an analysis of Data attributes in HTML elements and creates a <markup>
  1589. * based on each data type.
  1590. *
  1591. * @namespace LUNGO.Boot
  1592. * @class Data
  1593. * @requires Zepto
  1594. *
  1595. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  1596. * @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
  1597. */
  1598. LUNGO.Boot.Data = (function(lng, undefined) {
  1599. /**
  1600. * Initialize the <markup> data-attributes analisys
  1601. *
  1602. * @method init
  1603. *
  1604. *
  1605. */
  1606. var start = function() {
  1607. var attributes = lng.Attributes.Data;
  1608. for (var attribute in attributes) {
  1609. if (lng.Core.isOwnProperty(attributes, attribute)) {
  1610. _findElements(attributes[attribute]);
  1611. }
  1612. }
  1613. };
  1614. var _findElements = function(attribute) {
  1615. var elements = lng.Dom.query(attribute.selector);
  1616. for (var i = 0, len = elements.length; i < len; i++) {
  1617. var element = lng.Dom.query(elements[i]);
  1618. lng.View.Template.Binding.dataAttribute(element, attribute);
  1619. }
  1620. };
  1621. return {
  1622. start: start
  1623. };
  1624. })(LUNGO);
  1625. /**
  1626. * Initialize the automatic DOM UI events
  1627. *
  1628. * @namespace LUNGO.Boot
  1629. * @class Events
  1630. *
  1631. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  1632. * @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
  1633. */
  1634. LUNGO.Boot.Events = (function(lng, undefined) {
  1635. /**
  1636. * Initializes the automatic subscription events by markup of the project.
  1637. *
  1638. * @method init
  1639. *
  1640. */
  1641. var start = function() {
  1642. var touch_move_event = 'TOUCH_MOVE';
  1643. var touch_start_event = 'TOUCH_START';
  1644. var orientation_change = 'ORIENTATION_CHANGE';
  1645. var target_selector = 'a[href][data-target]';
  1646. var target_selector_from_aside = 'ASIDE a[href][data-target]';
  1647. lng.Dom.Event.listener(document, touch_move_event, _iScroll);
  1648. lng.Dom.Event.listener(window, orientation_change, _changeOrientation);
  1649. lng.Dom.Event.live(target_selector_from_aside, touch_start_event, _toggleAside);
  1650. lng.Dom.Event.live(target_selector, touch_start_event, _loadTarget);
  1651. };
  1652. var _iScroll = function(event_handler) {
  1653. event_handler.preventDefault();
  1654. };
  1655. var _changeOrientation = function(event) {
  1656. lng.View.Resize.toolbars();
  1657. };
  1658. var _toggleAside = function(event) {
  1659. event.preventDefault();
  1660. var link = lng.Dom.query(this);
  1661. var section_id = _getParentIdOfElement(link);
  1662. lng.View.Aside.toggle(section_id);
  1663. };
  1664. var _loadTarget = function(event) {
  1665. event.preventDefault();
  1666. var link = lng.Dom.query(this);
  1667. _selectTarget(link);
  1668. };
  1669. var _selectTarget = function(link) {
  1670. var target_type = link.data('target');
  1671. switch(target_type) {
  1672. case 'section':
  1673. var target_id = link.attr('href');
  1674. _goSection(target_id);
  1675. break;
  1676. case 'article':
  1677. _goArticle(link);
  1678. break;
  1679. case 'aside':
  1680. _goAside(link);
  1681. break;
  1682. }
  1683. };
  1684. var _goSection = function(id) {
  1685. if (id === '#back') {
  1686. lng.Router.back();
  1687. } else {
  1688. lng.Router.section(id);
  1689. }
  1690. };
  1691. var _goArticle = function(element) {
  1692. var section_id = _getParentIdOfElement(element);
  1693. var article_id = element.attr('href');
  1694. lng.Router.article(section_id, article_id);
  1695. };
  1696. var _goAside = function(element) {
  1697. var section_id = _getParentIdOfElement(element);
  1698. lng.View.Aside.toggle(section_id);
  1699. };
  1700. var _getParentIdOfElement = function(element) {
  1701. var parent_id = '#' + element.parents('section').attr('id');
  1702. return parent_id;
  1703. };
  1704. return {
  1705. start: start
  1706. };
  1707. })(LUNGO);
  1708. /**
  1709. * Initialize the <section> element
  1710. *
  1711. * @namespace LUNGO.Boot
  1712. * @class Section
  1713. * @requires Zepto
  1714. *
  1715. * @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
  1716. * @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
  1717. */
  1718. LUNGO.Boot.Section = (function(lng, undefined) {
  1719. var SELECTORS = {
  1720. ARTICLE: 'article',
  1721. SECTION: 'section'
  1722. };
  1723. var ACTIVE_CLASS = 'current';
  1724. /**
  1725. * Initializes all <section>s of the project
  1726. *
  1727. * @method init
  1728. */
  1729. var start = function() {
  1730. var sections = lng.Dom.query(SELECTORS.SECTION);
  1731. var easing_transition = '-webkit-transform 0.3s ease-in-out';
  1732. _initFirstSection(sections);
  1733. _initAllSections(sections);
  1734. lng.View.Resize.toolbars();
  1735. _allocateEasingTransition(sections, easing_transition);
  1736. };
  1737. var _initFirstSection = function(sections) {
  1738. var first_section = sections.first();
  1739. var first_section_id = '#' + first_section.attr('id');
  1740. first_section.addClass(ACTIVE_CLASS);
  1741. lng.Router.History.add(first_section_id);
  1742. };
  1743. var _initAllSections = function(sections) {
  1744. for (var i = 0, len = sections.length; i < len; i++) {
  1745. var section = lng.Dom.query(sections[i]);
  1746. _initSection(section);
  1747. _initFirstArticle(section);
  1748. }
  1749. };
  1750. var _initSection = function(section) {
  1751. var section_attributes = lng.Attributes.Section;
  1752. for (var attribute in section_attributes) {
  1753. if (lng.Core.isOwnProperty(section_attributes, attribute)) {
  1754. var property = section_attributes[attribute];
  1755. lng.View.Resize.article(section, property.name, property.bind, property.reference);
  1756. }
  1757. }
  1758. };
  1759. var _allocateEasingTransition = function(sections, easing) {
  1760. var transition_property = { '-webkit-transition': easing };
  1761. sections.css(transition_property);
  1762. };
  1763. var _initFirstArticle = function(section) {
  1764. section.children(SELECTORS.ARTICLE).first().addClass(ACTIVE_CLASS);
  1765. };
  1766. return {
  1767. start: start
  1768. };
  1769. })(LUNGO);