index.js 21 KB

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