lungo-1.0.2.js 52 KB

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