index.js 22 KB

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