index.js 23 KB

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