index.js 23 KB

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