123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839 |
- // TODO - Add initial page loading and handlers
- (function($,History,console){
- //"use strict";
- var State = History.getState(),
- Old = {},
- Key = null,
- flags = [],
- actions = [],
- templates = [],
- flag = window.flag = function(name,value){
- if(exists(value)){
- flags[name] = value;
- return value;
- }else{
- return exists(flags[name])?flags[name]:false;
- }
- },
- settings = {},
- exists = window.exists = function(v){
- return typeof v != 'undefined';
- },
- get = window.get = function(s){
- return exists(settings[s])?settings[s]:null;
- },
- set = window.set = function(s,v){
- settings[s] = v;
- return v;
- },
- setKey = window.setKey = function(key){
- if(key !== null){
- console.log('Key change to '+key);
- Key = key;
- var d = new Date();
- d.setTime(d.getTime()+get('expire'));
- $.cookie('key',key,{
- expires: d,
- path: '/'
- });
- }else{
- console.log('Key deleted');
- Key = null;
- $.removeCookie('key');
- }
- },
- getKey = window.getKey = function(){
- return Key;
- },
- templateHash = function(type,name){
- for(var i in templates){
- if(templates[i].name == name && templates[i].type == type){
- return templates[i].hash;
- }
- }
- return false;
- },
- action = window.action = function(name){
- if(exists(actions[name])){
- if(actions[name] instanceof Array){
- }else{
- loadState(actions[name]);
- return true;
- }
- }
- return false;
- },
- template = window.template = function(type,name,template,hash){
- var id = (function(type,name){
- for(var i in templates){
- if(templates[i].name == name && templates[i].type == type){
- return i;
- }
- }
- return false;
- })(type,name);
- if(exists(template)){
- if(template === null){
- if(id!==false){
- templates.splice(id,1);
- }
- $.localStorage('templates',templates);
- console.log('Dropping template for '+type+':'+name);
- }else{
- var o = {
- name: name,
- template: template,
- type: type,
- hash: typeof hash == 'undefined'?'':hash
- };
- if(id===false){
- console.log('Storing new template for '+type+':'+name);
- templates.push(o);
- }else{
- console.log('Replacing old template for '+type+':'+name);
- templates[id] = o;
- }
- $.localStorage('templates',templates);
- }
- }else if(id!==false){
- console.log('Using cached template for '+type+':'+name);
- return templates[id].template;
- }else{
- console.log('No cached template stored for: '+type+':'+name);
- }
- return '';
- },
- apiCall = window.apiCall = function(data,callback,background){
- console.log('apiCall('+data.type+'-'+data.id+')');
- if(!flag('error')){
- if(exists(background)&&!background){
- loading(true);
- }
- data.get = 'api';
- data.back = State.data.back;
- data.timestamp = +new Date;
- $.get(location.href,data,function(d){
- if(exists(d['error'])){
- error(d);
- }
- if(exists(d.state)){
- d.state.title = (d.state.title+'').capitalize();
- if(location.href.substr(location.href.lastIndexOf('/')+1) != d.state.url && d.state.url !== ''){
- console.log('Forced redirection to '+d.state.url);
- flag('handled',true);
- d.state.data.back = State.data.back;
- History.replaceState(d.state.data,d.state.title,d.state.url);
- callback = function(){
- location.reload();
- };
- }
- document.title = d.state.title;
- loading(false);
- }
- if(exists(callback)){
- console.log('Running apiCall callback');
- try{
- callback(d);
- }catch(e){
- error(e);
- }
- }
- },'json');
- }
- },
- loadState = window.loadState = function(href,callback){
- console.log('loadState('+href+')');
- if(!flag('error')){
- loading(true);
- var data = {
- get:'state',
- timestamp: +new Date,
- back: location.href
- };
- ajax = $.ajax(href,{
- data: data,
- async: true,
- type: 'GET',
- success: function(d){
- if(exists(d['error'])){
- error(d);
- }else{
- d.state.title = d.state.title.capitalize();
- d.state.url = href;
- console.log('pushState: '+d.state.title+'['+href+']');
- flag('handled',true);
- History.pushState(d.state.data,d.state.title,href);
- getNewState();
- }
- if(exists(callback)){
- callback(d);
- }
- if(!exists(d['error'])){
- flag('handled',true);
- stateChange();
- }
- },
- error: function(x,t,e){
- error({
- error: '['+t+'] '+e
- });
- if(exists(callback)){
- callback({
- error: '['+t+'] '+e
- });
- }
- },
- dataType: 'json'
- });
- }
- },
- replaceState = window.replaceState = function(href,callback){
- console.log('apiState('+href+')');
- if(!flag('error')){
- loading(true);
- var data = {
- get:'state',
- timestamp: +new Date,
- back: State.data.back
- };
- $.ajax(href,{
- data: data,
- async: true,
- type: 'GET',
- success: function(d){
- if(exists(d.error)){
- error(d);
- }else{
- d.state.title = d.state.title.capitalize();
- d.state.url = href;
- flag('handled',true);
- console.log('pushState: '+d.state.title+'['+href+']');
- History.replaceState(d.state.data,d.state.title,href);
- getNewState();
- }
- if(exists(callback)){
- callback(d);
- }
- console.log(d.state.title);
- if(!exists(d['error'])){
- flag('handled',true);
- stateChange();
- }
- },
- error: function(x,t,e){
- error({
- error: '['+t+'] '+e
- });
- if(exists(callback)){
- callback({
- error: '['+t+'] '+e
- });
- }
- },
- dataType: 'json'
- });
- }
- },
- error = window.error = function(e,callback){
- if(!flag('error')){
- flag('error',true);
- var msg = '['+State.url+'] '+(typeof e.error != 'undefined'?e.error:e);
- console.error((msg.trim()+"\n"+(exists(e.state)?JSON.stringify(e.state):'')).trim());
- alert(msg.trim(),'Error',callback);
- console.trace();
- console.log(e);
- }
- },
- getNewState = function(state){
- State = History.getState();
- console.log("State change: ["+State.title+"] "+JSON.stringify(State.data));
- if(!window.location.origin){
- window.location.origin = window.location.protocol + "//" + window.location.hostname + (window.location.port ? ':' + window.location.port: '');
- }
- },
- stateChange = function(){
- getNewState();
- if(!equal(State.data,Old)){
- switch(State.data.type){
- case 'page':case 'user':case 'project':case 'issue':case 'scrum':
- apiCall(State.data,function(d){
- if(!exists(d.error)){
- if(exists(d.context)){
- if(!exists(d.context.key)&&Key!==null){
- console.log('Context detected console.logout');
- setKey(null);
- }
- actions = [];
- if(exists(d.topbar)){
- render.topbar(template('topbars',d.topbar.template),d.topbar.context);
- if(exists(d.topbar.context.actions)){
- actions = d.topbar.context.actions;
- }
- }
- if(exists(d.sidebar)){
- render.sidebar(template('sidebars',d.sidebar.template),d.sidebar.context);
- }
- if(exists(d.template)){
- console.log('Using template: '+d.template.type+':'+d.template.name);
- d.template = template(d.template.type,d.template.name);
- render.content(d.template,d.context);
- }else{
- console.log('No template used');
- }
- if(!exists(d.toolbar)){
- $('#toolbar').parent().hide();
- }
- $(window).resize();
- loading(false);
- }else if(d.state.url != location.href){
- console.error('No context given');
- console.log(d);
- back();
- }
- }else{
- error(d);
- back();
- }
- flag('handled',false);
- });
- break;
- case 'action':break;
- default:
- error({
- url: State.url,
- error: "Unable to make a request of type "+State.data.type
- });
- }
- Old = State.data;
- }else{
- console.log(State.data,Old);
- console.warn('Stopped double load of '+Old.type+'-'+Old.id);
- loading(false);
- flag('handled',false);
- }
- },
- equal = function(o1,o2){
- for(var i in o1){
- if(!exists(o2[i])||o2[i]!=o1[i]){
- return false;
- }
- }
- for(i in o2){
- if(!exists(o1[i])||o2[i]!=o1[i]){
- return false;
- }
- }
- return true;
- },
- render = window.render = {
- topbar: function(t,c){
- $('#topbar').html(Handlebars.compile(t)(c));
- if(State.url == location.origin+'/page-index'){
- $('#topbar').find('.topbar-history').hide();
- }
- $('#topbar').addClass('overflow-hide');
- $('#topbar .icon-back').click(function(){
- back();
- });
- $('#topbar h1').text($('#topbar h1').text().capitalize());
- $('#topbar .icon-menu').click(function(){
- if($('#drawer').hasClass('open')){
- $('#drawer').removeClass('open').css('transform','');
- }else{
- $('#drawer').addClass('open').css('transform','translateX(80%)');
- }
- });
- $('#topbar .icon-add').click(function(){
- action('new');
- });
- render.links('#topbar');
- },
- sidebar: function(t,c){
- $('#sidebar').html(Handlebars.compile(t)(c));
- $('#toolbar-done').click(function(){
- $('#drawer').removeClass('open').css('transform','');
- });
- render.links('#sidebar');
- $('#sidebar').find('a').click(function(e){
- $('#drawer').removeClass('open').css('transform','');
- e.preventDefault();
- return false;
- });
- },
- content: function(t,c){
- $(document).unbind('ready');
- $('#content').html(
- Handlebars.compile(t)(c)
- );
- render.refresh('#content');
- },
- refresh: function(selector){
- render.links(selector);
- render.buttons(selector);
- render.time(selector);
- $(window).resize();
- },
- time: function(selector){
- $(selector).find('time.timeago').each(function(){
- var time = new Date($(this).text()*1000);
- $(this).replaceWith(
- $('<abbr>').attr({
- 'title': time.toISOString(),
- 'style': $(this).attr('style')
- }).addClass($(this).attr('class')).timeago()
- );
- });
- },
- buttons: function(selector){
- $(selector).find('.more').off().each(function(){
- var t = $(this);
- if(!$.hasData(t)){
- t.data('type',t.text().trim());
- t.data('at',t.prev().children().length);
- t.text('Load More');
- }
- if(t.prev().children().length < 10){
- t.hide();
- }
- }).click(function(){
- var t = $(this),
- data = {
- type: 'action',
- id: 'more',
- pid: State.data.id,
- url: State.url,
- title: State.title,
- topbar: false,
- no_state: true,
- of: t.data('type'),
- at: Number(t.data('at'))
- };
- data.start = t.data('at');
- apiCall(data,function(d){
- d.template = exists(d.template)?d.template:'comment';
- var tmplt = Handlebars.compile(template('pages',d.template)),
- i;
- if(d.messages.length < 10){
- t.hide();
- }
- for(i in d.messages){
- try{
- t.prev().append(
- tmplt(d.messages[i])
- );
- }catch(e){
- console.log("Could not load message: ",d.messages[i],e);
- }
- render.refresh(t.prev());
- }
- t.data('at',t.prev().children().length);
- },true);
- }).button();
- render.comment.buttons(selector);
- },
- comment: {
- buttons: function(selector){
- $(selector).find('.comment').each(function(){
- var context = JSON.parse($(this).text());
- $(this).text(context.text);
- $(this).button();
- $(this).click(function(){
- render.comment.dialog(context.id,context.type,context.title);
- });
- });
- },
- dialog: function(id,type,title){
- loading(true);
- flag('ignore_statechange',true);
- $('#comment').find('form').find('input[name=comment_type]').val(type);
- $('#comment').find('form').find('input[name=comment_id]').val(id);
- $('#comment').find('form').find('textarea[name=message]').val('');
- $('#comment').dialog({
- close: function(){
- $('#comment').find('form').find('input[name=comment_type]').val('');
- $('#comment').find('form').find('input[name=comment_id]').val('');
- flag('ignore_statechange',false);
- loading(false);
- },
- resizable: false,
- draggable: false,
- title: title,
- buttons: [
- {
- text: 'Ok',
- class: 'recommend-force',
- click: function(){
- var diag = $(this),
- context = diag.find('form').serializeObject();
- if(context.message !== ''){
- context.type = 'action';
- context.id = 'comment';
- context.url = State.url;
- context.title = State.title;
- apiCall(context,function(d){
- if(!exists(d.error)){
- diag.dialog('close');
- flag('ignore_statechange',false);
- stateChange();
- }
- });
- }
- }
- },{
- text: 'Cancel',
- class: 'cancel-force',
- click: function(){
- $(this).dialog('close');
- }
- }
- ]
- });
- },
- },
- dialog: function(selector,title){
- $(selector).dialog({
- close: function(){
- flag('error',false);
- var fn = $(this).data('callback');
- if(exists(fn)){
- fn();
- }
- loading(false);
- },
- resizable: false,
- draggable: false,
- title: title,
- buttons: [
- {
- text: 'Ok',
- class: 'recommend-force',
- click: function(){
- $(this).dialog('close');
- }
- }
- ]
- });
- },
- links: function(selector){
- $(selector).find('a').each(function(){
- var href = this.href;
- if(href.indexOf('#')!=-1&&(href.indexOf(location.origin)!=-1||href.indexOf('#')===0)){
- href = href.substr(href.indexOf('#')+1);
- $(this).click(function(e){
- try{
- loadState(href);
- }catch(error){
- console.error(error);
- }
- e.preventDefault();
- return false;
- });
- }
- });
- }
- },
- back = window.back = function(reload){
- console.log('reload',exists(reload));
- if(exists(State.data.back)){
- flag('handled',true);
- if(!History.back()){
- loadState(State.data.back);
- }else{
- stateChange();
- }
- }else if(State.data.type != 'page' || State.data.id != 'index'){
- if(exists(reload)){
- console.log('FORCING RELOAD');
- location.assign('page-index');
- }else{
- console.log('FORCING LOADSTATE');
- loadState('page-index');
- }
- }else{
- location.reload();
- }
- },
- alert = function(text,title,callback){
- if(exists(text)){
- title=exists(title)?title:'';
- callback=exists(callback)?callback:function(){};
- $('#dialog').text(text).data('callback',callback);
- render.dialog('#dialog',title,callback);
- }
- },
- hasFocus = function(){
- if(typeof document.hasFocus === 'undefined'){
- document.hasFocus = function(){
- return document.visibilityState == 'visible';
- };
- }
- return document.hasFocus();
- },
- notify = window.notify = function(title,text,onclick,onclose){
- var notification;
- if(exists(window['Notification'])&&!exists(window.webkitNotifications)&&!flag('default_notify')){
- if(Notification.permission === 'denied'){
- flag('default_notify',true);
- notify(title,text,onclick,onclose);
- }else if(Notification.permission === 'granted'){
- notification = new Notification(title,{
- body: text,
- icon: location.origin+'/img/favicon.ico'
- });
- notification.onclick = onclick;
- notification.onclose = onclose;
- }else{
- Notification.requestPermission(function(p){
- console.log('permission for notify: '+p);
- Notification.permission = p;
- notify(title,text,onclick,onclose);
- });
- }
- }else if(exists(window.navigator.mozNotification)){
- notification = window.navigator.mozNotification.createNotification(title,text,location.origin+'/img/favicon.ico');
- notification.onclick = onclick;
- notification.onclose = onclose;
- notification.show();
- }else{
- $('#notification-container').notify('create',{
- title: title,
- text: text,
- click: onclick,
- close: onclose
- });
- }
- },
- loading = function(state){
- if(!flag('ignore_statechange')){
- state = exists(state)?state:false;
- console.log('loading state '+state);
- if(!flag('error') && !state){
- $('#loading').hide();
- }else if(state){
- $('#loading').show();
- }
- }
- },
- debug = window.debug = {
- hardReload: function(){
- debug.clearCache();
- location.reload();
- },
- clearCache: function(){
- templates = [];
- $.localStorage('templates',null);
- console.log('Templates cleared.');
- },
- manifesto: function(){
- if(!flag('manifesto')){
- if(window.applicationCache){
- if(window.applicationCache.status==window.applicationCache.UNCACHED){
- $('head').append(
- $('<script>').attr({
- 'type': 'text/javascript',
- 'src': 'http://manifesto.ericdelabar.com/manifesto.js?x="+(Math.random())'
- })
- );
- (function wait(){
- if($('#cacheStatus').length === 0){
- setTimeout(wait,10);
- }else{
- $('#cacheStatus').niceScroll();
- }
- })();
- }else{
- alert("Manifest file is valid.");
- }
- }else{
- alert("This browser does not support HTML5 Offline Application Cache.");
- }
- flag('manifesto',true);
- }
- },
- firebug: function(){
- if(!flag('firebug-lite')){
- $('head').append(
- $('<script>').attr({
- 'type': 'text/javascript',
- 'src': 'https://getfirebug.com/firebug-lite.js#startOpened',
- 'id': 'FirebugLite'
- })
- );
- $('<image>').attr('src','https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png');
- flag('firebug-lite',true);
- }
- }
- },
- getTemplates = function(callback){
- var fn = function(type,callback){
- $.get('api.php',{
- type: 'manifest',
- id: type
- },function(d){
- if(!exists(d.error)){
- var count = d.manifest.length;
- for(var i in d.manifest){
- console.log('Loading template('+(Number(i)+1)+'/'+d.manifest.length+'): '+d.manifest[i].name);
- if(templateHash(type,d.manifest[i].name) !== d.manifest[i].hash){
- $.get('api.php',{
- type: 'template',
- id: type,
- name: d.manifest[i].name
- },function(d){
- template(d.type,d.name,d.template,d.hash);
- $.localStorage('templates',templates);
- count--;
- console.log('Loaded template('+count+' left): '+d.name);
- },'json');
- }else{
- count--;
- }
- }
- setTimeout(function wait_for_templates(){
- if(count === 0){
- console.log('getTemplates callback');
- callback();
- }else{
- setTimeout(wait_for_templates,10);
- }
- },10);
- }else{
- error(d.error);
- }
- },'json');
- };
- fn('topbars',function(){
- fn('sidebars',function(){
- fn('pages',function(){
- callback();
- });
- });
- });
- };
- if(exists($.cookie('key'))){
- setKey($.cookie('key'));
- }else{
- setKey(null);
- }
- $(document).ready(function(){
- if(exists(window['Notification'])&&exists(Notification.permission)&&Notification.permission !== 'granted'){
- Notification.requestPermission();
- }
- $.ajaxSetup({
- async: false,
- cache: false,
- timeout: 30000 // 30 seconds
- });
- $(document).ajaxError(function(event, request, settings) {
- error({error:'Request timed out'});
- });
- if(!exists($.support.touch)){
- $.support.touch = 'ontouchstart' in window || 'onmsgesturechange' in window;
- }
- $('#content,#topbar').click(function(){
- $('.menu').hide();
- });
- $(window).resize(function(){
- if($(window).width()>767){
- $('#topbar div.topbar-right, #topbar div.topbar-left').css({
- 'display': ''
- });
- }
- });
- $.get(location.href,{
- get: 'settings',
- timestamp: +new Date,
- back: false,
- no_state: true
- },function(d){
- if(!exists(d.error)){
- settings = d.settings;
- if(d.version != $.localStorage('version')){
- $.localStorage('version',d.version);
- $.localStorage('templates',null);
- templates = [];
- }else{
- templates = $.localStorage('templates');
- if(templates === null){
- templates = [];
- }
- }
- getTemplates(function(){
- replaceState(location.href);
- (function notifications(){
- var context = State;
- context.type = 'action';
- context.id = 'notifications';
- context.url = State.url;
- context.title = State.title;
- context.topbar = false;
- context.no_state = true;
- apiCall(context,function(d){
- if(!exists(d.error)){
- if(d.count>0 && $.localStorage('last_pm_check') < d.timestamp){
- notify('Alert','You have '+d.count+' new message'+(d.count>1?'s':''),function(){
- loadState('page-messages');
- });
- }
- $('.topbar-notifications').css('display',d.count>0?'block':'').text('('+d.count+')');
- $.localStorage('last_pm_check',d.timestamp);
- }
- setTimeout(notifications,5*1000); // every 5 seconds
- },true);
- })();
- });
- }else{
- error(d.error);
- }
- },'json');
- $(window).on('statechange',function(){
- if(!flag('handled')){
- console.log('unhandled state change event');
- console.trace();
- stateChange();
- }else{
- flag('handled',false);
- }
- });
- var getState = History.getState;
- History.getState = function(flag){
- if(exists(flag)){
- return State;
- }else{
- return getState.call(History);
- }
- };
- $('#notification-container').notify();
- });
- shortcut.add('f12',function(){
- debug.firebug();
- });
- shortcut.add('Ctrl+f12',function(){
- debug.manifesto();
- });
- shortcut.add('Shift+f12',function(){
- debug.clearCache();
- });
- $.fn.serializeObject = function(){
- var o = {},
- a = this.serializeArray();
- $.each(a,function(){
- if(o[this.name] !== undefined){
- if(!o[this.name].push){
- o[this.name] = [o[this.name]];
- }
- o[this.name].push(this.value || '');
- }else{
- o[this.name] = this.value || '';
- }
- });
- return o;
- };
- String.prototype.capitalize = function(lower) {
- return (lower?this.toLowerCase():this).replace(/(?:^|\s)\S/g, function(a){
- return a.toUpperCase();
- });
- };
- })(jQuery,History,console);
|