index.js 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894
  1. // TODO - Add initial page loading and handlers
  2. (function($,History,console){
  3. var State = History.getState(),
  4. Old = {},
  5. Key = null,
  6. flags = [],
  7. actions = [],
  8. templates = [],
  9. flag = window.flag = function(name,value){
  10. if(exists(value)){
  11. flags[name] = value;
  12. }else{
  13. return exists(flags[name])?flags[name]:false;
  14. }
  15. },
  16. settings = {},
  17. exists = function(v){
  18. return typeof v != 'undefined';
  19. },
  20. get = window.get = function(s){
  21. return settings[s];
  22. },
  23. set = window.set = function(s,v){
  24. settings[s] = v;
  25. return v;
  26. },
  27. setKey = window.setKey = function(key){
  28. if(key !== null){
  29. console.log('Key change to '+key);
  30. Key = key;
  31. var d = new Date();
  32. d.setTime(d.getTime()+get('expire'));
  33. $.cookie('key',key,{
  34. expires: d
  35. });
  36. }else{
  37. console.log('Key deleted');
  38. Key = null;
  39. $.removeCookie('key');
  40. }
  41. },
  42. getKey = window.getKey = function(){
  43. return Key;
  44. },
  45. templateHash = function(type,name){
  46. for(var i in templates){
  47. if(templates[i].name == name && templates[i].type == type){
  48. return templates[i].hash;
  49. }
  50. }
  51. return false;
  52. },
  53. action = window.action = function(name){
  54. if(exists(actions[name])){
  55. loadState(actions[name]);
  56. }
  57. },
  58. template = window.template = function(type,name,template,hash){
  59. var id = (function(type,name){
  60. for(var i in templates){
  61. if(templates[i].name == name && templates[i].type == type){
  62. return i;
  63. }
  64. }
  65. return false;
  66. })(type,name);
  67. if(exists(template)){
  68. if(template === null){
  69. if(id!==false){
  70. templates.splice(id,1);
  71. }
  72. $.localStorage('templates',templates);
  73. console.log('Dropping template for '+type+':'+name);
  74. return '';
  75. }else{
  76. var o = {
  77. name: name,
  78. template: template,
  79. type: type,
  80. hash: typeof hash == 'undefined'?'':hash
  81. };
  82. if(id===false){
  83. console.log('Storing new template for '+type+':'+name);
  84. templates.push(o);
  85. }else{
  86. console.log('Replacing old template for '+type+':'+name);
  87. templates[id] = o;
  88. }
  89. $.localStorage('templates',templates);
  90. }
  91. }else if(id!==false){
  92. console.log('Using cached template for '+type+':'+name);
  93. return templates[id].template;
  94. }else{
  95. console.log('No cached template stored for: '+type+':'+name);
  96. return '';
  97. }
  98. },
  99. apiCall = window.apiCall = function(data,callback,background){
  100. console.log('apiCall('+data.type+'-'+data.id+')');
  101. if(!flag('error')){
  102. if(exists(background)&&!background){
  103. loading(true);
  104. }
  105. data.get = 'api';
  106. data.back = State.data.back;
  107. data.timestamp = +new Date;
  108. $.get(location.href,data,function(d){
  109. if(exists(d['error'])){
  110. error(d);
  111. }
  112. if(exists(d.state)){
  113. d.state.title = (d.state.title+'').capitalize();
  114. if(location.href.substr(location.href.lastIndexOf('/')+1) != d.state.url && d.state.url !== ''){
  115. console.log('Forced redirection to '+d.state.url);
  116. flag('handled',true);
  117. d.state.data.back = State.data.back;
  118. History.replaceState(d.state.data,d.state.title,d.state.url);
  119. callback = function(){
  120. location.reload();
  121. };
  122. }
  123. document.title = d.state.title;
  124. loading(false);
  125. }
  126. if(exists(callback)){
  127. console.log('Running apiCall callback');
  128. try{
  129. callback(d);
  130. }catch(e){
  131. error(e);
  132. }
  133. }
  134. },'json');
  135. }
  136. },
  137. loadState = window.loadState = function(href,callback){
  138. console.log('loadState('+href+')');
  139. if(!flag('error')){
  140. loading(true);
  141. var data = {
  142. get:'state',
  143. timestamp: +new Date,
  144. back: location.href
  145. };
  146. ajax = $.ajax(href,{
  147. data: data,
  148. async: true,
  149. type: 'GET',
  150. success: function(d){
  151. if(exists(d['error'])){
  152. error(d);
  153. }else{
  154. d.state.title = d.state.title.capitalize();
  155. d.state.url = href;
  156. console.log('pushState: '+d.state.title+'['+href+']');
  157. flag('handled',true);
  158. History.pushState(d.state.data,d.state.title,href);
  159. getNewState();
  160. }
  161. if(exists(callback)){
  162. callback(d);
  163. }
  164. if(!exists(d['error'])){
  165. flag('handled',true);
  166. stateChange();
  167. }
  168. },
  169. error: function(x,t,e){
  170. error({
  171. error: '['+t+'] '+e
  172. });
  173. if(exists(callback)){
  174. callback({
  175. error: '['+t+'] '+e
  176. });
  177. }
  178. },
  179. dataType: 'json'
  180. });
  181. }
  182. },
  183. replaceState = window.replaceState = function(href,callback){
  184. console.log('apiState('+href+')');
  185. if(!flag('error')){
  186. loading(true);
  187. var data = {
  188. get:'state',
  189. timestamp: +new Date,
  190. back: State.data.back
  191. };
  192. $.ajax(href,{
  193. data: data,
  194. async: true,
  195. type: 'GET',
  196. success: function(d){
  197. if(exists(d['error'])){
  198. error(d);
  199. }else{
  200. d.state.title = d.state.title.capitalize();
  201. d.state.url = href;
  202. flag('handled',true);
  203. console.log('pushState: '+d.state.title+'['+href+']');
  204. History.replaceState(d.state.data,d.state.title,href);
  205. getNewState();
  206. }
  207. if(exists(callback)){
  208. callback(d);
  209. }
  210. console.log(d.state.title);
  211. if(!exists(d['error'])){
  212. flag('handled',true);
  213. stateChange();
  214. }
  215. },
  216. error: function(x,t,e){
  217. error({
  218. error: '['+t+'] '+e
  219. });
  220. if(exists(callback)){
  221. callback({
  222. error: '['+t+'] '+e
  223. });
  224. }
  225. },
  226. dataType: 'json'
  227. });
  228. }
  229. },
  230. error = window.error = function(e,callback){
  231. if(!flag('error')){
  232. flag('error',true);
  233. var msg = '['+State.url+'] '+(typeof e.error != 'undefined'?e.error:e);
  234. console.error((msg.trim()+"\n"+(exists(e.state)?JSON.stringify(e.state):'')).trim());
  235. alert(msg.trim(),'Error',callback);
  236. console.trace();
  237. console.log(e);
  238. }
  239. },
  240. getNewState = function(state){
  241. State = History.getState();
  242. console.log("State change: ["+State.title+"] "+JSON.stringify(State.data));
  243. if(!window.location.origin){
  244. window.location.origin = window.location.protocol + "//" + window.location.hostname + (window.location.port ? ':' + window.location.port: '');
  245. }
  246. },
  247. stateChange = function(){
  248. getNewState();
  249. if(!equal(State.data,Old)){
  250. switch(State.data.type){
  251. case 'page':case 'user':case 'project':case 'issue':case 'scrum':
  252. apiCall(State.data,function(d){
  253. if(!exists(d.error)){
  254. if(exists(d.context)){
  255. if(!exists(d.context.key)&&Key!==null){
  256. console.log('Context detected console.logout');
  257. setKey(null);
  258. }
  259. actions = [];
  260. if(exists(d.topbar)){
  261. render.topbar(template('topbars',d.topbar.template),d.topbar.context);
  262. if(exists(d.topbar.context.actions)){
  263. actions = d.topbar.context.actions;
  264. }
  265. }
  266. if(exists(d.sidebar)){
  267. render.sidebar(template('sidebars',d.sidebar.template),d.sidebar.context);
  268. }
  269. if(exists(d.template)){
  270. console.log('Using template: '+d.template.type+':'+d.template.name);
  271. d.template = template(d.template.type,d.template.name);
  272. render.content(d.template,d.context);
  273. }else{
  274. console.log('No template used');
  275. }
  276. $(window).resize();
  277. loading(false);
  278. }else if(d.state.url != location.href){
  279. console.error('No context given');
  280. console.log(d);
  281. back();
  282. }
  283. }else{
  284. error(d);
  285. back();
  286. }
  287. flag('handled',false);
  288. });
  289. break;
  290. case 'action':break;
  291. default:
  292. error({
  293. url: State.url,
  294. error: "Unable to make a request of type "+State.data.type
  295. });
  296. }
  297. Old = State.data;
  298. }else{
  299. console.log(State.data,Old);
  300. console.warn('Stopped double load of '+Old.type+'-'+Old.id);
  301. loading(false);
  302. flag('handled',false);
  303. }
  304. },
  305. equal = function(o1,o2){
  306. for(var i in o1){
  307. if(!exists(o2[i])||o2[i]!=o1[i]){
  308. return false;
  309. }
  310. }
  311. for(i in o2){
  312. if(!exists(o1[i])||o2[i]!=o1[i]){
  313. return false;
  314. }
  315. }
  316. return true;
  317. },
  318. render = window.render = {
  319. topbar: function(t,c){
  320. $('#topbar').html(Handlebars.compile(t)(c));
  321. if(State.url == location.origin+'/page-index'){
  322. $('#topbar').find('.topbar-history').hide();
  323. }
  324. $('#topbar').addClass('overflow-hide');
  325. $('#topbar .icon-back').click(function(){
  326. back();
  327. });
  328. $('#topbar h1').text($('#topbar h1').text().capitalize());
  329. $('#topbar .icon-menu').click(function(){
  330. if($('#drawer').hasClass('open')){
  331. $('#drawer').removeClass('open').css('transform','');
  332. }else{
  333. $('#drawer').addClass('open').css('transform','translateX(80%)');
  334. }
  335. });
  336. $('#topbar .icon-add').click(function(){
  337. action('new');
  338. });
  339. render.links('#topbar');
  340. },
  341. sidebar: function(t,c){
  342. $('#sidebar').html(Handlebars.compile(t)(c));
  343. $('#toolbar-done').click(function(){
  344. $('#drawer').removeClass('open').css('transform','');
  345. });
  346. render.links('#sidebar');
  347. $('#sidebar').find('a').click(function(e){
  348. $('#drawer').removeClass('open').css('transform','');
  349. e.preventDefault();
  350. return false;
  351. });
  352. },
  353. content: function(t,c){
  354. $(document).unbind('ready');
  355. $('#content').html(
  356. Handlebars.compile(t)(c)
  357. );
  358. render.form('#content');
  359. render.accordions('#content');
  360. render.refresh('#content');
  361. },
  362. refresh: function(selector){
  363. render.links(selector);
  364. render.buttons(selector);
  365. render.menus(selector);
  366. render.time(selector);
  367. $(window).resize();
  368. },
  369. time: function(selector){
  370. $(selector).find('time.timeago').each(function(){
  371. var time = new Date($(this).text()*1000);
  372. $(this).replaceWith(
  373. $('<abbr>').attr({
  374. 'title': time.toISOString(),
  375. 'style': $(this).attr('style')
  376. }).addClass($(this).attr('class')).timeago()
  377. );
  378. });
  379. },
  380. accordions: function(selector){
  381. $(selector).find('.accordion').each(function(){
  382. var icons = {};
  383. if($(this).children('.icons').length == 1){
  384. icons = JSON.parse($(this).children('.icons').text());
  385. }
  386. $(this).children('.icons').remove();
  387. $(this).accordion({
  388. collapsible: true,
  389. icons: icons,
  390. active: false
  391. });
  392. });
  393. },
  394. buttons: function(selector){
  395. $(selector).find('.more').off().each(function(){
  396. var t = $(this);
  397. if(!$.hasData(t)){
  398. t.data('type',t.text().trim());
  399. t.data('at',t.prev().children().length);
  400. t.text('Load More');
  401. }
  402. if(t.prev().children().length < 10){
  403. t.hide();
  404. }
  405. }).click(function(){
  406. var t = $(this),
  407. data = {
  408. type: 'action',
  409. id: 'more',
  410. pid: State.data.id,
  411. url: State.url,
  412. title: State.title,
  413. topbar: false,
  414. no_state: true,
  415. of: t.data('type'),
  416. at: Number(t.data('at'))
  417. };
  418. data.start = t.data('at');
  419. apiCall(data,function(d){
  420. var tmplt = Handlebars.compile(template('pages','comment')),
  421. i;
  422. if(d.messages.length < 10){
  423. t.hide();
  424. }
  425. for(i in d.messages){
  426. try{
  427. t.prev().append(
  428. tmplt(d.messages[i])
  429. );
  430. }catch(e){
  431. console.log("Could not load message: ",d.messages[i],e);
  432. }
  433. render.refresh(t.prev());
  434. }
  435. t.data('at',t.prev().children().length);
  436. },true);
  437. }).button();
  438. render.comment.buttons(selector);
  439. },
  440. comment: {
  441. buttons: function(selector){
  442. $(selector).find('.comment').each(function(){
  443. var context = JSON.parse($(this).text());
  444. $(this).text(context.text);
  445. $(this).button();
  446. $(this).click(function(){
  447. render.comment.dialog(context.id,context.type,context.title);
  448. });
  449. });
  450. },
  451. dialog: function(id,type,title){
  452. loading(true);
  453. flag('ignore_statechange',true);
  454. $('#comment').find('form').find('input[name=comment_type]').val(type);
  455. $('#comment').find('form').find('input[name=comment_id]').val(id);
  456. $('#comment').find('form').find('textarea[name=message]').val('');
  457. $('#comment').dialog({
  458. close: function(){
  459. $('#comment').find('form').find('input[name=comment_type]').val('');
  460. $('#comment').find('form').find('input[name=comment_id]').val('');
  461. flag('ignore_statechange',false);
  462. loading(false);
  463. },
  464. resizable: false,
  465. draggable: false,
  466. title: title,
  467. buttons: [
  468. {
  469. text: 'Ok',
  470. class: 'recommend-force',
  471. click: function(){
  472. var diag = $(this),
  473. context = diag.find('form').serializeObject();
  474. if(context.message !== ''){
  475. context.type = 'action';
  476. context.id = 'comment';
  477. context.url = State.url;
  478. context.title = State.title;
  479. apiCall(context,function(d){
  480. if(!exists(d.error)){
  481. diag.dialog('close');
  482. flag('ignore_statechange',false);
  483. $('.topbar-current').click();
  484. }
  485. });
  486. }
  487. }
  488. },{
  489. text: 'Cancel',
  490. class: 'cancel-force',
  491. click: function(){
  492. $(this).dialog('close');
  493. }
  494. }
  495. ]
  496. });
  497. },
  498. },
  499. menus: function(selector){
  500. $(selector).find('.menu').css({
  501. 'list-style':'none'
  502. }).menu({
  503. icons:{
  504. submenu: "ui-icon-circle-triangle-e"
  505. }
  506. }).removeClass('ui-corner-all').addClass('ui-corner-bottom').parent().click(function(e){
  507. e.stopPropagation();
  508. });
  509. },
  510. form: function(selector){
  511. render.inputs(selector);
  512. },
  513. inputs: function(selector){
  514. /*$(selector).find('input[type=text],input[type=password]').each(function(){
  515. var input = $(this),
  516. height = input.height()>=17?17:input.height();
  517. input.siblings('.input-clear').remove();
  518. input.off('focus').off('blur').after(
  519. $('<div>').css({
  520. position: 'absolute',
  521. right: $(window).width() - (input.outerWidth() + input.position().left)+2,
  522. top: input.position().top+2,
  523. 'background-image': 'url(img/headers/icons/clear.png)',
  524. 'background-position': 'center',
  525. 'background-size': height+'px '+height+'px',
  526. 'background-repeat': 'no-repeat',
  527. width: input.height(),
  528. height: input.height(),
  529. cursor: 'pointer'
  530. }).hide().addClass('input-clear').mousedown(function(){
  531. input.val('');
  532. })
  533. );
  534. input.focus(function(){
  535. input.next().show();
  536. }).blur(function(e){
  537. input.next().hide();
  538. });
  539. });
  540. $(selector).find('input[type=text],input[type=password],textarea').each(function(){
  541. var input = $(this);
  542. if(input.hasClass('fill-width')){
  543. input.css('width','calc(100% - '+(input.outerWidth()-input.width())+'px)');
  544. }
  545. });*/
  546. },
  547. dialog: function(selector,title){
  548. $(selector).dialog({
  549. close: function(){
  550. flag('error',false);
  551. var fn = $(this).data('callback');
  552. if(exists(fn)){
  553. fn();
  554. }
  555. loading(false);
  556. },
  557. resizable: false,
  558. draggable: false,
  559. title: title,
  560. buttons: [
  561. {
  562. text: 'Ok',
  563. class: 'recommend-force',
  564. click: function(){
  565. $(this).dialog('close');
  566. }
  567. }
  568. ]
  569. });
  570. },
  571. links: function(selector){
  572. $(selector).find('a').each(function(){
  573. var href = this.href;
  574. if(href.indexOf('#')!=-1&&(href.indexOf(location.origin)!=-1||href.indexOf('#')===0)){
  575. href = href.substr(href.indexOf('#')+1);
  576. $(this).click(function(e){
  577. try{
  578. loadState(href);
  579. }catch(error){
  580. console.error(error);
  581. }
  582. e.preventDefault();
  583. return false;
  584. });
  585. }
  586. });
  587. }
  588. },
  589. back = window.back = function(reload){
  590. console.log('reload',exists(reload));
  591. if(exists(State.data.back)){
  592. flag('handled',true);
  593. if(!History.back()){
  594. loadState(State.data.back);
  595. }else{
  596. stateChange();
  597. }
  598. }else if(State.data.type != 'page' || State.data.id != 'index'){
  599. if(exists(reload)){
  600. console.log('FORCING RELOAD');
  601. location.assign('page-index');
  602. }else{
  603. console.log('FORCING LOADSTATE');
  604. loadState('page-index');
  605. }
  606. }else{
  607. location.reload();
  608. }
  609. },
  610. alert = function(text,title,callback){
  611. if(exists(text)){
  612. title=exists(title)?title:'';
  613. callback=exists(callback)?callback:function(){};
  614. $('#dialog').text(text).data('callback',callback);
  615. render.dialog('#dialog',title,callback);
  616. }
  617. },
  618. hasFocus = function(){
  619. if(typeof document.hasFocus === 'undefined'){
  620. document.hasFocus = function(){
  621. return document.visibilityState == 'visible';
  622. };
  623. }
  624. return document.hasFocus();
  625. },
  626. notify = window.notify = function(title,text,onclick,onclose){
  627. var notification;
  628. if(exists(window['Notification'])&&!exists(window.webkitNotifications)&&!flag('default_notify')&&!hasFocus()){
  629. if(Notification.permission === 'denied'){
  630. flag('default_notify',true);
  631. notify(title,text,onclick,onclose);
  632. }else if(Notification.permission === 'granted'){
  633. notification = new Notification(title,{
  634. body: text,
  635. icon: location.origin+'/img/favicon.ico'
  636. });
  637. notification.onclick = onclick;
  638. notification.onclose = onclose;
  639. }else{
  640. Notification.requestPermission(function(p){
  641. console.log('permission for notify: '+p);
  642. Notification.permission = p;
  643. notify(title,text,onclick,onclose);
  644. });
  645. }
  646. }else if(exists(window.navigator.mozNotification)&&!hasFocus()){
  647. notification = window.navigator.mozNotification.createNotification(title,text,location.origin+'/img/favicon.ico');
  648. notification.onclick = onclick;
  649. notification.onclose = onclose;
  650. notification.show();
  651. }else{
  652. $('#notification-container').notify('create',{
  653. title: title,
  654. text: text,
  655. click: onclick,
  656. close: onclose
  657. });
  658. }
  659. },
  660. loading = function(state){
  661. if(!flag('ignore_statechange')){
  662. state = exists(state)?state:false;
  663. console.log('loading state '+state);
  664. if(!flag('error') && !state){
  665. $('#loading').hide();
  666. }else if(state){
  667. $('#loading').show();
  668. }
  669. }
  670. },
  671. debug = window.debug = {
  672. hardReload: function(){
  673. debug.clearCache();
  674. location.reload();
  675. },
  676. clearCache: function(){
  677. templates = [];
  678. $.localStorage('templates',null);
  679. console.log('Templates cleared.');
  680. },
  681. manifesto: function(){
  682. if(!flag('manifesto')){
  683. if(window.applicationCache){
  684. if(window.applicationCache.status==window.applicationCache.UNCACHED){
  685. $('head').append(
  686. $('<script>').attr({
  687. 'type': 'text/javascript',
  688. 'src': 'http://manifesto.ericdelabar.com/manifesto.js?x="+(Math.random())'
  689. })
  690. );
  691. (function wait(){
  692. if($('#cacheStatus').length === 0){
  693. setTimeout(wait,10);
  694. }else{
  695. $('#cacheStatus').niceScroll();
  696. }
  697. })();
  698. }else{
  699. alert("Manifest file is valid.");
  700. }
  701. }else{
  702. alert("This browser does not support HTML5 Offline Application Cache.");
  703. }
  704. flag('manifesto',true);
  705. }
  706. },
  707. firebug: function(){
  708. if(!flag('firebug-lite')){
  709. $('head').append(
  710. $('<script>').attr({
  711. 'type': 'text/javascript',
  712. 'src': 'https://getfirebug.com/firebug-lite.js#startOpened',
  713. 'id': 'FirebugLite'
  714. })
  715. );
  716. $('<image>').attr('src','https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png');
  717. flag('firebug-lite',true);
  718. }
  719. }
  720. },
  721. getTemplates = function(callback){
  722. var fn = function(type,callback){
  723. $.get('api.php',{
  724. type: 'manifest',
  725. id: type
  726. },function(d){
  727. if(!exists(d.error)){
  728. var count = d.manifest.length;
  729. for(var i in d.manifest){
  730. console.log('Loading template('+(Number(i)+1)+'/'+d.manifest.length+'): '+d.manifest[i].name);
  731. if(templateHash(type,d.manifest[i].name) !== d.manifest[i].hash){
  732. $.get('api.php',{
  733. type: 'template',
  734. id: type,
  735. name: d.manifest[i].name
  736. },function(d){
  737. template(d.type,d.name,d.template,d.hash);
  738. $.localStorage('templates',templates);
  739. count--;
  740. console.log('Loaded template('+count+' left): '+d.name);
  741. },'json');
  742. }else{
  743. count--;
  744. }
  745. }
  746. setTimeout(function wait_for_templates(){
  747. if(count === 0){
  748. console.log('getTemplates callback');
  749. callback();
  750. }else{
  751. setTimeout(wait_for_templates,10);
  752. }
  753. },10);
  754. }else{
  755. error(d.error);
  756. }
  757. },'json');
  758. };
  759. fn('topbars',function(){
  760. fn('sidebars',function(){
  761. fn('pages',function(){
  762. callback();
  763. });
  764. });
  765. });
  766. };
  767. if(exists($.cookie('key'))){
  768. setKey($.cookie('key'));
  769. }else{
  770. setKey(null);
  771. }
  772. $(document).ready(function(){
  773. if(exists(window['Notification'])&&exists(Notification.permission)&&Notification.permission !== 'granted'){
  774. Notification.requestPermission();
  775. }
  776. $.ajaxSetup({
  777. async: false,
  778. cache: false,
  779. timeout: 30000 // 30 seconds
  780. });
  781. $(document).ajaxError(function(event, request, settings) {
  782. error({error:'Request timed out'});
  783. });
  784. if(!exists($.support.touch)){
  785. $.support.touch = 'ontouchstart' in window || 'onmsgesturechange' in window;
  786. }
  787. $('#content,#topbar').click(function(){
  788. $('.menu').hide();
  789. });
  790. $(window).resize(function(){
  791. if($(window).width()>767){
  792. $('#topbar div.topbar-right, #topbar div.topbar-left').css({
  793. 'display': ''
  794. });
  795. }
  796. render.inputs('#content');
  797. render.inputs('#topbar');
  798. });
  799. $.get(location.href,{
  800. get: 'settings',
  801. timestamp: +new Date,
  802. back: false,
  803. no_state: true
  804. },function(d){
  805. if(!exists(d.error)){
  806. settings = d.settings;
  807. if(d.version != $.localStorage('version')){
  808. $.localStorage('version',d.version);
  809. $.localStorage('templates',null);
  810. templates = [];
  811. }else{
  812. templates = $.localStorage('templates');
  813. if(templates === null){
  814. templates = [];
  815. }
  816. }
  817. getTemplates(function(){
  818. replaceState(location.href);
  819. (function notifications(){
  820. var context = State;
  821. context.type = 'action';
  822. context.id = 'notifications';
  823. context.url = State.url;
  824. context.title = State.title;
  825. context.topbar = false;
  826. context.no_state = true;
  827. apiCall(context,function(d){
  828. if(!exists(d.error)){
  829. if(d.count>0 && $.localStorage('last_pm_check') < d.timestamp){
  830. notify('Alert','You have '+d.count+' new message'+(d.count>1?'s':''),function(){
  831. loadState('page-messages');
  832. });
  833. }
  834. $('.topbar-notifications').css('display',d.count>0?'block':'').text('('+d.count+')');
  835. $.localStorage('last_pm_check',d.timestamp);
  836. }
  837. setTimeout(notifications,5*1000); // every 5 seconds
  838. },true);
  839. })();
  840. });
  841. }else{
  842. error(d.error);
  843. }
  844. },'json');
  845. $(window).on('statechange',function(){
  846. if(!flag('handled')){
  847. console.log('unhandled state change event');
  848. console.trace();
  849. stateChange();
  850. }else{
  851. flag('handled',false);
  852. }
  853. });
  854. var getState = History.getState;
  855. History.getState = function(flag){
  856. if(exists(flag)){
  857. return State;
  858. }else{
  859. return getState.call(History);
  860. }
  861. };
  862. $('#notification-container').notify();
  863. });
  864. shortcut.add('f12',function(){
  865. debug.firebug();
  866. });
  867. shortcut.add('Ctrl+f12',function(){
  868. debug.manifesto();
  869. });
  870. shortcut.add('Shift+f12',function(){
  871. debug.clearCache();
  872. });
  873. $.fn.serializeObject = function(){
  874. var o = {},
  875. a = this.serializeArray();
  876. $.each(a,function(){
  877. if(o[this.name] !== undefined){
  878. if(!o[this.name].push){
  879. o[this.name] = [o[this.name]];
  880. }
  881. o[this.name].push(this.value || '');
  882. }else{
  883. o[this.name] = this.value || '';
  884. }
  885. });
  886. return o;
  887. };
  888. String.prototype.capitalize = function(lower) {
  889. return (lower?this.toLowerCase():this).replace(/(?:^|\s)\S/g, function(a){
  890. return a.toUpperCase();
  891. });
  892. };
  893. })(jQuery,History,console);