PageRenderTime 50ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 1ms

/xplorer/js/forkan.js

https://bitbucket.org/itkane/forkan
JavaScript | 768 lines | 404 code | 160 blank | 204 comment | 7 complexity | 4e252a784143e58232dddeee8db5a709 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. // usage: log('inside coolFunc', this, arguments);
  2. // paulirish.com/2009/log-a-lightweight-wrapper-for-consolelog/
  3. window.log = function(){
  4. log.history = log.history || []; // store logs to an array for reference
  5. log.history.push(arguments);
  6. if(this.console) {
  7. arguments.callee = arguments.callee.caller;
  8. var newarr = [].slice.call(arguments);
  9. (typeof console.log === 'object' ? log.apply.call(console.log, console, newarr) : console.log.apply(console, newarr));
  10. }
  11. };
  12. // make it safe to use console.log always
  13. (function(b){function c(){}for(var d="assert,count,debug,dir,dirxml,error,exception,group,groupCollapsed,groupEnd,info,log,timeStamp,profile,profileEnd,time,timeEnd,trace,warn".split(","),a;a=d.pop();){b[a]=b[a]||c}})((function(){try
  14. {console.log();return window.console;}catch(err){return window.console={};}})());
  15. // Load the application once the DOM is ready, using `jQuery.ready`:
  16. $(function(){
  17. var cfg ={};
  18. cfg = {
  19. ApiServer : "http://127.0.0.1/forkan/api/",
  20. version : "2.0",
  21. key : "28e336ac6c9423d946ba02d19c6a2632",
  22. riwaya : "1", // riwaya [1:hafs 2:warch ...]
  23. tafseer : "1", // Tafseer [1:tabari 2:jalalyn ...]
  24. telawa : "1", // Telawa [1:Sudais 2:Afasy ...]
  25. StartPage : "50",
  26. NavigationMethod: 0,//[0: (d) Navigation with Quran page(604p), 1: custome per ayas]
  27. url : function(){
  28. return /*'http://localhost/forkan/xplorer/'*/this.ApiServer + this.version +'/'+ this.key ;
  29. }
  30. };
  31. //#############################################################################
  32. //-------------------------------------- Aya ----------------------------------
  33. // Aya Model
  34. var modAya = Backbone.Model.extend({
  35. // Our basic **Aya** model has [index, sura, aya, text, riwaya, audio and views] attributes.
  36. defaults: {
  37. //yid : 0,
  38. //sur : 0,
  39. snm : 0,//sura name (from suras)
  40. //aya : 0,
  41. //txt : '',
  42. rwy : 0,/*,
  43. audio : '',
  44. views : 0,*/
  45. active : false
  46. },
  47. // index
  48. idAttribute: "yid",
  49. initialize: function() {
  50. if(_.isUndefined(this.get('yid'))){
  51. //this.destroy();
  52. //alert('empty');
  53. }
  54. else{
  55. //--- make attr more readable then "array[x]
  56. this.set({yid : this.get("yid"),
  57. sur : this.get("sur"),
  58. aya : this.get("aya"),
  59. txt : this.get("txt")
  60. //"riwaya": this.get("rw")
  61. });
  62. //alert(JSON.stringify(this));
  63. }
  64. },
  65. focus: function() {
  66. this.set({"active" :true});
  67. },
  68. blur: function() {
  69. this.set({"active" :true});
  70. },
  71. clear: function() {
  72. this.destroy();
  73. }
  74. });
  75. // Ayas Collection
  76. var colAyas = Backbone.Collection.extend({
  77. // Reference to this collection's model.
  78. model: modAya,
  79. /*url: function(){
  80. //var arg={cls:"q",act:"get",ayaID:1,nbr:17};
  81. return "/aya";
  82. },*/
  83. parse: function(response) {
  84. return response.dt;
  85. },
  86. // Filter down the list of all todo items that are finished.
  87. /*done: function() {
  88. return this.filter(function(todo){ return todo.get('done'); });
  89. },*/
  90. // Ayas are sorted by their original insertion order.
  91. comparator: function(mod) {
  92. return mod.get('order');
  93. }
  94. });
  95. // Aya Item View
  96. var viewAya = Backbone.View.extend({
  97. //... is a list tag.
  98. tagName: "span",
  99. className:"iAyaCon",
  100. //el: $(".iAya"),
  101. // Cache the template function for a single item.
  102. template: _.template($('#aya-template').html()),
  103. SideTemplate : _.template($('#side-template').html()),
  104. // The DOM events specific to an item.
  105. events: {
  106. "hover .iAya" : "iHover",
  107. "click .iAya" : "iFocus"
  108. },
  109. initialize: function() {
  110. _.bindAll(this, 'render', 'close'/*, 'remove'*/);
  111. this.model.bind('change', this.render);
  112. this.model.bind('destroy', this.remove);
  113. },
  114. // Re-render the contents of the todo item.
  115. render: function() {
  116. var aya = this;
  117. /*var pg = Forkan.Pages.find(function(page){
  118. (page.get('pid') == aya.model.get('sur')) { aya.model.set({'snm':sura.get('nam')});}
  119. return (sura.get('sid') == aya.model.get('sur'));});*/
  120. aya.model.set({'snm':Forkan.Suras.get(aya.model.get('sur')).get('nam')});
  121. //aya.model.set({'pid':Forkan.Pages.get(aya.model.get('sur')).get('nam')});
  122. $(this.el).html(this.template(this.model.toJSON()));
  123. return this;
  124. },
  125. // On Hover on Aya.
  126. iHover: function() {
  127. $(this.el).find(".iAya").toggleClass("ayaHover");
  128. },
  129. // On click or focus on Aya.
  130. iFocus: function() {
  131. $(".iAya").removeClass("ayaActive");
  132. $(this.el).find(".iAya").addClass("ayaActive");
  133. $("#iside").html(this.SideTemplate(this.model.toJSON()));
  134. var aya = this;
  135. // change currents breadcrumbe
  136. Forkan.Suras.get(aya.model.get('sur')).active();
  137. /*var ss = Forkan.Suras.models;
  138. var ps = Forkan.Pages.models;
  139. //alert(JSON.stringify(ss[5].get('sta')));
  140. var p = Forkan.Pages.find(function(page){
  141. if(page.get('pid')){
  142. var p1 = ps[page.get('pid')]; //console.log('p1='+p1.get('pid'));
  143. var p2 = ps[(parseInt(page.get('pid'))+1)]; //console.log('p2='+p1.get('pid'));
  144. var sur = ss[page.get('sur')];//console.log('s1='+sur.get('sid'));
  145. var sur2= ss[p2.get('sur')]; //console.log('s2='+sur2.get('sid'));
  146. var start = parseInt(sur.get('sta'))+parseInt(page.get('aya'))-1;
  147. var end = sur2.get('sta') ;
  148. //var end = start + page.get('pid')+1].get('ays');
  149. console.log('s:'+start+' e:'+end+' y:'+aya.model.get('yid'));
  150. //console.log('p1='+p1.get('pid')+' p2='+p2.get('pid')+' s1='+sur.get('sid')+' s2='+sur2.get('sid'));
  151. return (aya.model.get('yid') >= start) && (aya.model.get('yid') < end);
  152. }
  153. });
  154. //alert(JSON.stringify(p));
  155. p.active();
  156. */
  157. },
  158. close: function() {
  159. $(this.el).unbind();
  160. $(this.el).empty();
  161. },
  162. // Remove the item, destroy the model.
  163. clear: function() {
  164. this.model.clear();
  165. }
  166. });
  167. // maybe add AyasView 4 search result
  168. // Ayas List View
  169. var viewAyas = Backbone.View.extend({
  170. el: $('#ipage'),
  171. initialize: function() {
  172. this.model.bind("reset", this.render, this);
  173. },
  174. render: function(eventName) {
  175. //$(this.el).empty();
  176. _.each(this.model.models, function(iModel) {
  177. //TODO: add cfg 4: append vs prepend
  178. if(!_.isUndefined(iModel.get('yid'))){
  179. $(this.el).prepend(
  180. new viewAya({model: iModel}).render().el);
  181. }
  182. }, this);
  183. //this.last.
  184. //$('.iAya').first().click();
  185. return this;
  186. }
  187. });
  188. //#############################################################################
  189. //---------------------------------- Pages ------------------------------------
  190. // Page Item Model
  191. var modPage = Backbone.Model.extend({
  192. //urlRoot: cfg.url()+"/page",
  193. defaults: {
  194. "pid": 0,
  195. "sur": "",
  196. "aya": ""
  197. },
  198. // index
  199. idAttribute: "pid",
  200. initialize: function() {
  201. //if (!this.get("index")) {
  202. //this.destroy();
  203. //};
  204. //--- make attr more readable then "array[x]
  205. this.set({"pid" : this.get("pid"),
  206. "sur" : this.get("sur"),
  207. "aya" : this.get("aya")
  208. });
  209. //alert(JSON.stringify(this));
  210. }
  211. });
  212. // Page Item View
  213. var viewPage = Backbone.View.extend({
  214. tagName: "li",
  215. template: _.template($('#page-template').html()),
  216. events: {
  217. "click .iPage" : "select"
  218. },
  219. initialize: function() {
  220. this.model.bind("change", this.render, this);
  221. this.model.bind("destroy", this.close, this);
  222. },
  223. render: function(eventName) {
  224. $(this.el).html(this.template(this.model.toJSON()));
  225. return this;
  226. },
  227. select: function() {
  228. var page = this.model;
  229. this.active();
  230. Forkan.navigate("ayas/page/"+page.get("pid"), true);
  231. },
  232. active: function() {
  233. var page = this.model;
  234. $('#activePage').html(page.get('pid'));
  235. },
  236. close: function() {
  237. $(this.el).unbind();
  238. $(this.el).remove();
  239. }
  240. });
  241. // Pages List Collection
  242. var colPages = Backbone.Collection.extend({
  243. model : modPage,
  244. url : function(){
  245. return 'ayas/page';
  246. },
  247. parse: function(response) {
  248. return response.dt;
  249. }
  250. });
  251. // Pages List View
  252. var viewPages = Backbone.View.extend({
  253. el: $('#pageList'),
  254. initialize: function() {
  255. this.model.bind("reset", this.render, this);
  256. },
  257. render: function(eventName) {
  258. _.each(this.model.models, function(iModel) {
  259. //TODO: add cfg 4: append vs prepend
  260. $(this.el).prepend(
  261. new viewPage({model: iModel}).render().el);
  262. }, this);
  263. return this;
  264. }
  265. });
  266. //#############################################################################
  267. //-------------------------------- Suras Collection ---------------------------
  268. // Sura Item Model
  269. var modSura = Backbone.Model.extend({
  270. //[start, ayas, order, rukus, name, tname, ename, type] attributes.
  271. //[0, 7, 5, 1, '???????', "Al-Faatiha", 'The Opening', 'Meccan'],
  272. defaults: {
  273. /* sid : 0,
  274. sta : 0,
  275. ays : 0,
  276. ord : 0,
  277. rukus : 0,
  278. nam : '',
  279. tnm : '',
  280. enm : '',
  281. typ : '',
  282. audio : ''*/
  283. },
  284. // index
  285. idAttribute: "sid",
  286. initialize: function() {
  287. if(_.isUndefined(this.get('0'))){
  288. //this.destroy();
  289. //alert('empty');
  290. }
  291. else{
  292. //--- make attr more readable then "array[x]
  293. this.set({"sta" : this.get("1"),
  294. "sid" : this.get("0"),
  295. "ays" : this.get("2"),
  296. "ord" : this.get("3"),
  297. //"rukus" : this.get("rukus"),
  298. "nam" : this.get("5"),
  299. //"tname" : this.get("tname"),
  300. "enm" : this.get("4"),
  301. "typ" : this.get("6")
  302. //"audio" : this.get("audio")
  303. //"riwaya": this.get("rw")
  304. });
  305. //alert(JSON.stringify(this));
  306. //alert(JSON.stringify(this.get('5')));
  307. }
  308. },
  309. active: function(){
  310. $('#activeSura').html(this.get('nam'));
  311. },
  312. // Remove this Todo from *localStorage* and delete its view.
  313. clear: function() {
  314. this.destroy();
  315. }
  316. });
  317. // Suras List Collection
  318. var colSuras = Backbone.Collection.extend({
  319. model: modSura,
  320. /*url: function(){
  321. return '/sura';//+cfg.StartAya+"/nbr=15";
  322. },*/
  323. parse: function(response) {
  324. return response.dt;
  325. }
  326. });
  327. // Sura Item View
  328. var viewSura = Backbone.View.extend({
  329. tagName: "li",
  330. className:"iSuraCon",
  331. template: _.template($('#sura-template').html()),
  332. events: {
  333. "click .iSura" : "select"
  334. },
  335. initialize: function() {
  336. this.model.bind("change", this.render, this);
  337. this.model.bind("destroy", this.close, this);
  338. },
  339. render: function(eventName) {
  340. $(this.el).html(this.template(this.model.toJSON()));
  341. return this;
  342. },
  343. select: function() {
  344. var sura = this.model;
  345. this.active();
  346. Forkan.navigate("ayas/"+(sura.get("sta"))+'/to/'+sura.get("ays"), true);
  347. },
  348. active: function() {
  349. var sura = this.model;
  350. $('#activeSura').html(sura.get('nam'));
  351. },
  352. close: function() {
  353. $(this.el).unbind();
  354. $(this.el).remove();
  355. }
  356. });
  357. // Sura List View
  358. var viewSuras = Backbone.View.extend({
  359. el: $('#suraList'),
  360. initialize: function() {
  361. this.model.bind("reset", this.render, this);
  362. this.model.bind("active", this.active, this);
  363. },
  364. render: function(eventName) {
  365. $(this.el).empty();
  366. _.each(this.model.models, function(iModel) {
  367. //TODO: add cfg 4: append vs prepend
  368. if(!_.isUndefined(iModel.get('sid'))){
  369. $(this.el).prepend(
  370. new viewSura({model: iModel}).render().el);
  371. }
  372. }, this);
  373. return this;
  374. },
  375. active: function() {
  376. var sura = this.model;
  377. $('#activeSura').html(sura.get('nam'));
  378. }
  379. });
  380. // The Application
  381. // ---------------
  382. //var Ayas = new colAyas;
  383. //var Suras = new colSuras;
  384. //var Ayas = new colAyas;
  385. // Our overall **AppView** is the top-level piece of UI.
  386. var AppView = Backbone.View.extend({
  387. // Instead of generating a new element, bind to the existing skeleton of
  388. // the App already present in the HTML.
  389. el: $("#forkanApp"),
  390. // Our template for the line of statistics at the bottom of the app.
  391. //statsTemplate: _.template($('#stats-template').html()),
  392. // Delegated events for creating new items, and clearing completed ones.
  393. events: {
  394. //"keypress #new-todo": "createOnEnter",
  395. //"keyup #new-todo": "showTooltip",
  396. //"click .iSura": "GotoSura",
  397. //"click .mark-all-done": "toggleAllComplete"
  398. },
  399. initialize: function() {
  400. //_.bindAll(this, 'addAya', 'addAyas', 'addSura', 'addSuras', 'render');/, 'toggleAllComplete'
  401. //this.input = this.$("#new-todo");
  402. //this.allCheckbox = this.$(".mark-all-done")[0];
  403. /*Forkan.Ayas.bind('add', this.render);
  404. Forkan.Ayas.bind('reset', this.render);
  405. Forkan.Ayas.bind('all', this.render);
  406. Forkan.Suras.bind('add', this.render);
  407. Forkan.Suras.bind('reset', this.render);
  408. Forkan.Suras.bind('all', this.render);*/
  409. },
  410. // Re-rendering the App just means refreshing the statistics -- the rest
  411. // of the app doesn't change.
  412. render: function() {
  413. $("*[rel=twipsy]").twipsy({
  414. live: true
  415. });
  416. $("*[rel=popover]")
  417. .popover({
  418. offset: 10
  419. })
  420. .click(function(e) {
  421. e.preventDefault()
  422. });
  423. $('.dropdown').dropdown();
  424. },
  425. // Add a single todo item to the list by creating a view for it, and
  426. // appending its element to the `<ul>`.
  427. addAya: function(aya) {
  428. var view = new viewAya({model: aya});
  429. this.$("#ipage").prepend(view.render().el);
  430. },
  431. // Add all items in the **Todos** collection at once.
  432. addAyas: function() {
  433. Ayas.each(this.addAya);
  434. },
  435. // Add a single todo item to the list by creating a view for it, and
  436. // appending its element to the `<ul>`.
  437. addSura: function(sura) {
  438. var view = new viewSura({model: sura});
  439. $("#suraList").append(view.render().el);
  440. },
  441. // Add all items in the **Todos** collection at once.
  442. addSuras: function() {
  443. Suras.each(this.addSura);
  444. },
  445. // Generate the attributes for a new Todo item.
  446. newAttributes: function() {
  447. }
  448. // Lazily show the tooltip that tells you to press `enter` to save
  449. // a new todo item, after one second.
  450. /*showTooltip: function(e) {
  451. var tooltip = this.$(".ui-tooltip-top");
  452. var val = this.input.val();
  453. tooltip.fadeOut();
  454. if (this.tooltipTimeout) clearTimeout(this.tooltipTimeout);
  455. if (val == '' || val == this.input.attr('placeholder')) return;
  456. var show = function(){ tooltip.show().fadeIn(); };
  457. this.tooltipTimeout = _.delay(show, 1000);
  458. },*/
  459. });
  460. var AppRouter = Backbone.Router.extend({
  461. routes: {
  462. "ayas/:id/to/:nbr" : "getAyas",
  463. "ayas/page/:id" : "getAyasPerPage",
  464. "ayas/page/:id/:yid": "gotoAyaInPage",
  465. "page" : "getPages",
  466. "" : "home",
  467. },
  468. init: function(){
  469. var self = this;
  470. // initialize All object
  471. this.Ayas = new colAyas();
  472. this.Suras = new colSuras();
  473. this.Suras.fetch({
  474. url : cfg.ApiServer + cfg.version +'/'+ cfg.key+'/suras',
  475. success: function() {
  476. self.SurasView = new viewSuras({model: self.Suras});
  477. self.SurasView.render();
  478. //if (self.requestedId) self.getAya(self.requestedId);
  479. /*self.Ayas.fetch({
  480. url : cfg.url()+"/ayas/page/"+cfg.StartPage,
  481. success: function() {
  482. self.AyasView = new viewAyas({model: self.Ayas});
  483. self.AyasView.render();
  484. // focus in first aya
  485. $('.iAya').first().click();
  486. //if (self.requestedId) self.getAya(self.requestedId);
  487. }
  488. });*/
  489. Backbone.history.start();
  490. }
  491. });
  492. Forkan.Ayas.bind('add', this.irender);
  493. Forkan.Ayas.bind('reset', this.irender);
  494. Forkan.Ayas.bind('all', this.irender);
  495. Forkan.Suras.bind('add', this.irender);
  496. Forkan.Suras.bind('reset', this.irender);
  497. Forkan.Suras.bind('all', this.irender);
  498. this.Pages = new colPages();
  499. this.Pages.fetch({
  500. url : cfg.ApiServer + cfg.version +'/'+ cfg.key+'/pages',
  501. success: function() {
  502. self.PagesView = new viewPages({model: self.Pages});
  503. self.PagesView.render();
  504. //if (self.requestedId) self.getAya(self.requestedId);
  505. $('#pg'+cfg.startPage).click();
  506. }
  507. });
  508. },
  509. irender: function() {
  510. $("*[rel=twipsy]").twipsy({
  511. live: true
  512. });
  513. $("*[rel=popover]")
  514. .popover({
  515. offset: 10
  516. })
  517. .click(function(e) {
  518. e.preventDefault()
  519. });
  520. $('.dropdown').dropdown();
  521. },
  522. home: function() {
  523. var self = this;
  524. if (!self.requestedId){
  525. self.Ayas.fetch({
  526. url : cfg.url()+"/ayas/page/"+cfg.StartPage,
  527. success: function() {
  528. self.AyasView = new viewAyas({model: self.Ayas});
  529. self.AyasView.render();
  530. // focus in first aya
  531. $('.iAya').first().click();
  532. //if (self.requestedId) self.getAya(self.requestedId);
  533. }
  534. });}
  535. },
  536. getAyas: function(id,nbr) {
  537. var self = this;
  538. self.requestedId = id;
  539. //if (!this.Ayas){this.init();}
  540. $("#ipage").animate({right: '-500px'},"700",function() { $(this).hide().empty() });
  541. this.Ayas.fetch({
  542. url : cfg.url()+"/ayas/"+id+"/to/"+nbr,
  543. success: function() {
  544. //$("#ipage").slideDown();
  545. $("#ipage").animate({right: '0px'},"700",function() { $(this).show() });
  546. /* ; //self.AyasView = new viewAyas({model: self.Ayas});
  547. //self.AyasView.render();
  548. //if (self.requestedId) self.wineDetails(self.requestedId);*/
  549. }
  550. });
  551. } ,
  552. getAyasPerPage: function(id) {
  553. var self = this;
  554. self.requestedId = id;
  555. //if (!this.Ayas){this.init();}
  556. $("#ipage").animate({right: '-500px'},"700",function() { $(this).hide().empty() });
  557. this.Ayas.fetch({
  558. url : cfg.url()+"/ayas/page/"+id,
  559. success: function() {
  560. //$("#ipage").slideDown();
  561. $("#ipage").animate({right: '0px'},"700",function() { $(this).show() });
  562. // focus in first aya
  563. $('.iAya').first().click();
  564. }
  565. });
  566. } ,
  567. gotoAyaInPage: function(id,yid) {
  568. var self = this;
  569. self.requestedId = id;
  570. //if (!this.Ayas){this.init();}
  571. $("#ipage").animate({right: '-500px'},"700",function() { $(this).hide().empty() });
  572. this.Ayas.fetch({
  573. url : cfg.url()+"/ayas/page/"+id,
  574. success: function() {
  575. //$("#ipage").slideDown();
  576. $("#ipage").animate({right: '0px'},"700",function() { $(this).show();
  577. $("#ya"+yid).click(); });
  578. // focus in aya
  579. /* ; //self.AyasView = new viewAyas({model: self.Ayas});
  580. //self.AyasView.render();
  581. //if (self.requestedId) self.wineDetails(self.requestedId);*/
  582. }
  583. });
  584. } ,
  585. getPages: function() {
  586. var self = this;
  587. //if (!this.Ayas){this.init();}
  588. this.Pages.fetch({
  589. url : cfg.hh.url()+"/aya/"+id+"/to/"+nbr/* ;
  590. success: function() {
  591. $("#ipage").empty();
  592. //self.AyasView = new viewAyas({model: self.Ayas});
  593. //self.AyasView.render();
  594. //if (self.requestedId) self.wineDetails(self.requestedId);
  595. }*/
  596. });
  597. }
  598. });
  599. var Forkan = new AppRouter();
  600. Forkan.init();
  601. Forkan.view = new AppView;
  602. //var header = new HeaderView();
  603. // Finally, we kick things off by creating the **App**.
  604. });