lungo-1.0.0.js 49 KB

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