lungo-1.0.0.js 49 KB

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