index.js 23 KB

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