lungo-1.0.4.js 55 KB

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