PageRenderTime 58ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 1ms

/tags/2009-07-09/fe/assets/js/base-1.16.js

https://github.com/traviskuhl/twittangle
JavaScript | 2373 lines | 1281 code | 585 blank | 507 comment | 380 complexity | 016d0fee8f940d543ad1ac665ff23a0c MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. // globals
  2. var $Y = YAHOO,
  3. $d = YAHOO.util.Dom,
  4. $e = YAHOO.util.Event,
  5. $c = YAHOO.util.Connect,
  6. $a = YAHOO.util.Anim,
  7. $j = YAHOO.lang.JSON,
  8. $ = YAHOO.util.Dom.get;
  9. /* loading function */
  10. var $l = function(on) {
  11. // scroll top
  12. var t = $d.getDocumentScrollTop();
  13. // show it
  14. $d.setStyle('loading','display',(on?'block':'none'));
  15. $d.setStyle('loading','height',$d.getDocumentHeight()+'px');
  16. $d.setY('loading-wrap',parseInt($d.getDocumentScrollTop(),10)+100 );
  17. }
  18. /* overload */
  19. var inArray = function(ary,obj) {
  20. for ( var i = 0; i < ary.length; i++ ) {
  21. if ( ary[i] == obj ) {
  22. return true;
  23. }
  24. }
  25. return false;
  26. }
  27. /* yui defer loading */
  28. var foldGroup = new YAHOO.util.ImageLoader.group(window, 'scroll', null);
  29. foldGroup.className = 'defer';
  30. foldGroup.foldConditional = true;
  31. foldGroup.addTrigger(window, 'resize');
  32. /* namespace Twit */
  33. $Y.namespace('twitTangle');
  34. // scope
  35. //(function(){
  36. // is good target
  37. $d.isGoodTarget = function( el, cl, limit ) {
  38. // limit
  39. if ( !limit ) { limit = 5; }
  40. var i = 0;
  41. if ( typeof cl == 'object' ) {
  42. while ( el && typeof el.tagName != 'undefined' && el.tagName.toLowerCase() != cl.tag.toLowerCase() && i < limit ) {
  43. el = el.parentNode;
  44. i++;
  45. }
  46. if ( typeof el.tagName != 'undefined' && el.tagName.toLowerCase() == cl.tag.toLowerCase() ) {
  47. return el;
  48. }
  49. }
  50. else {
  51. while ( el && !$d.hasClass(el,cl) && i < limit ) {
  52. el = el.parentNode;
  53. i++;
  54. }
  55. if ( $d.hasClass(el,cl) ) {
  56. return el;
  57. }
  58. }
  59. // false
  60. return false;
  61. }
  62. /* timeline function */
  63. $Y.twitTangle.Global = function(p) {
  64. this.init(p);
  65. }
  66. /* extend */
  67. $Y.twitTangle.Global.prototype = {
  68. // params
  69. params : {},
  70. rated : {},
  71. tagged: {},
  72. flags: {},
  73. // init
  74. init : function(p) {
  75. // fold
  76. foldGroup.fetch();
  77. // global params
  78. this.params = p;
  79. // add our first entry
  80. dsHistory.addFunction( this.loadXhrPage, this, location.href );
  81. // execute
  82. $e.on(window,'load',TT.executeQueue,window,true);
  83. // click
  84. $e.on(document.body,'click',function(e){
  85. // target
  86. var tar = $e.getTarget(e);
  87. var oTar = tar;
  88. // link
  89. if ( $d.hasClass(tar,'do-reply') ) {
  90. // stop
  91. $e.stopEvent(e);
  92. // open
  93. this.doReply(tar);
  94. }
  95. else if ( $d.hasClass(tar,'do-fav') ) {
  96. // stop
  97. $e.stopEvent(e);
  98. // fav
  99. this.doFav(tar);
  100. }
  101. else if ( $d.hasClass(tar,'rate') ) {
  102. // stop
  103. $e.stopEvent(e);
  104. // rate
  105. this.openRate(tar);
  106. }
  107. else if ( $d.hasClass(tar,'do-rate') ) {
  108. // stop
  109. $e.stopEvent(e);
  110. // do
  111. this.doRate(tar);
  112. }
  113. else if ( $d.hasClass(tar,'toggle-upload-pic') ) {
  114. $e.stopEvent(e);
  115. if ( $d.hasClass('pic-upload','open') ) {
  116. $d.removeClass('pic-upload','open');
  117. }
  118. else {
  119. $d.addClass('pic-upload','open');
  120. }
  121. }
  122. else if ( $d.hasClass(tar,'close-rate') ) {
  123. // stop
  124. $e.stopEvent(e);
  125. // fade in
  126. $d.setXY('Rate',[-999,-999]);
  127. // fade
  128. var a = new $a('bd',{'opacity':{to:1}},.3);
  129. a.animate();
  130. }
  131. else if ( $d.hasClass(tar,'tag') ) {
  132. // stop
  133. $e.stopEvent(e);
  134. // do it
  135. this.openTag(tar);
  136. }
  137. else if ( $d.hasClass(tar,'close-tag') ) {
  138. // stop
  139. $e.stopEvent(e);
  140. // fade in
  141. $d.setXY('Tag',[-999,-999]);
  142. // fade
  143. var a = new $a('bd',{'opacity':{to:1}},.3);
  144. a.animate();
  145. }
  146. else if ( $d.hasClass(tar,'do-tag') ) {
  147. // stop
  148. $e.stopEvent(e);
  149. // do tag
  150. this.doTag(tar);
  151. }
  152. else if ( $d.hasClass(tar,'group') ) {
  153. // stop
  154. $e.stopEvent(e);
  155. // do it
  156. this.openGroup(tar);
  157. }
  158. else if ( $d.hasClass(tar,'close-group') ) {
  159. // stop
  160. $e.stopEvent(e);
  161. // fade in
  162. $d.setXY('Group',[-999,-999]);
  163. // get groups
  164. var ul = $('Group').getElementsByTagName('ul')[0].getElementsByTagName('li');
  165. // go for each val
  166. for ( var i = 0; i < ul.length; i++ ) {
  167. var box = ul[i].getElementsByTagName('input')[0];
  168. box.checked = false;
  169. }
  170. // fade
  171. var a = new $a('bd',{'opacity':{to:1}},.3);
  172. a.animate();
  173. }
  174. else if ( $d.hasClass(tar,'do-group') ) {
  175. // stop event
  176. $e.stopEvent(e);
  177. // save
  178. this.doGroup(tar);
  179. }
  180. else if ( $d.hasClass(tar,'create-group') ) {
  181. // stop
  182. $e.stopEvent(e);
  183. $d.setStyle('NewGroupWrap','opacity','0');
  184. $d.setStyle('NewGroupWrap','display','block');
  185. // open
  186. var a = new $a('NewGroupWrap',{'opacity':{'to':1}},.2);
  187. a.animate();
  188. // focus
  189. $('NewGroup').focus();
  190. }
  191. else if ( $d.hasClass(tar,'do-create-group') ) {
  192. // stop
  193. $e.stopEvent(e);
  194. // post the
  195. window.location.href = "/groups?do=create&name="+escape( $('NewGroup').value );
  196. }
  197. else if ( $d.hasClass(tar,'delete-group') ) {
  198. // stop
  199. $e.stopEvent(e);
  200. // do it
  201. this.deleteGroup(tar);
  202. }
  203. else if ( $d.hasClass(tar,'view-pic') ) {
  204. // no event
  205. $e.stopEvent(e);
  206. // do it
  207. this.doPic(tar);
  208. }
  209. else if ( $d.hasClass(tar,'view-video') ) {
  210. // no event
  211. $e.stopEvent(e);
  212. // do it
  213. this.doVideo(tar);
  214. }
  215. else if ( $d.hasClass(tar,'view-expand') ) {
  216. // no event
  217. $e.stopEvent(e);
  218. // get info
  219. var info = tar.id.split('|');
  220. // get link
  221. $(info[1]).innerHTML = $(info[1]).href;
  222. // remove
  223. tar.parentNode.removeChild(tar);
  224. }
  225. else if ( ( tar = $d.isGoodTarget(oTar,{'tag':'a'}) ) ) {
  226. // check the target
  227. var href = tar.href;
  228. var reg = false;
  229. // regex
  230. if ( location.href.indexOf('https:') !== -1 ) {
  231. reg = new RegExp("https:\/\/(www\.|networks\.)?twittangle\.com");
  232. }
  233. else {
  234. reg = new RegExp("http:\/\/(www\.|networks\.)?twittangle\.com");
  235. }
  236. // lets check to see if the
  237. // url is the right subdomain
  238. if ( !href.match(reg) || href.indexOf('#') != -1 ) {
  239. return;
  240. }
  241. // abort last call
  242. if ( this.lastXhrPageReq ) {
  243. $c.abort(this.lastXhrPageReq);
  244. }
  245. // stop event
  246. $e.stopEvent(e);
  247. // blur
  248. oTar.blur();
  249. // load some xhr
  250. this.loadXhrPage(href);
  251. }
  252. },this,true);
  253. // mouse over
  254. $e.on('doc','mouseover',this.mouseOver,this,true);
  255. $e.on('doc','mouseout',this.mouseOut,this,true);
  256. // create reply window
  257. this.reply = new YAHOO.widget.Panel("reply", {
  258. 'width': "600px",
  259. 'visible': false,
  260. 'text': '',
  261. 'constraintoviewport': true,
  262. 'fixedcenter': true,
  263. 'modal': true,
  264. 'draggable': false,
  265. 'effect': {effect:YAHOO.widget.ContainerEffect.FADE,duration:0.25}
  266. });
  267. var html = "<h2 id='reply-hd'></h2>" +
  268. "<textarea id='reply-text'></textarea> <button id='reply-submit'>Update</button>" +
  269. "<span id='reply-chars'>140</span>" +
  270. "<blockquote id='reply-quote'></blockquote>" +
  271. "<div class='saving'><em>Sending...</em></div>";
  272. // set body
  273. this.reply.setBody(html);
  274. // render
  275. this.reply.render(document.body);
  276. // attach events
  277. $e.on('reply-submit','click',this.submitReply,this,true);
  278. $e.on('reply-text','keypress',function(){
  279. var len = parseInt($('reply-text').value.length,10);
  280. var l = (140 - len);
  281. $('reply-chars').innerHTML = l;
  282. // what
  283. if ( l < 0 ) {
  284. $d.setStyle('reply-chars','color','red');
  285. $('reply-submit').disabled = true;
  286. }
  287. else {
  288. $d.setStyle('reply-chars','color','#555');
  289. $('reply-submit').disabled = false;
  290. }
  291. });
  292. // get height of content
  293. var ch = parseInt($d.getStyle('Content','height'),10);
  294. var mh = parseInt($d.getStyle('yui-main','height'),10);
  295. // check main
  296. if ( mh < ch ) {
  297. // get b
  298. var el = $d.getElementsByClassName('yui-b','div',$('yui-main'))[0];
  299. if ( el ) {
  300. $d.setStyle(el,'height',ch+'px');
  301. }
  302. }
  303. },
  304. // mouse over
  305. mouseOver : function(e) {
  306. // tar
  307. var tar = $e.getTarget(e);
  308. if ( (tar = $d.isGoodTarget(tar,'status')) ) {
  309. if ( tar.tagName.toLowerCase() == 'li' ) {
  310. $d.addClass(tar,'on');
  311. }
  312. }
  313. },
  314. mouseOut : function(e) {
  315. // tar
  316. var tar = $e.getTarget(e);
  317. if ( (tar = $d.isGoodTarget(tar,'status')) ) {
  318. if ( tar.tagName.toLowerCase() == 'li' ) {
  319. $d.removeClass(tar,'on');
  320. }
  321. }
  322. },
  323. /* submit update */
  324. submitUpdate : function(e) {
  325. // stop
  326. $e.stopEvent(e);
  327. // val
  328. var update = $('update-txt').value;
  329. // callback
  330. var callback = {
  331. 'success': function(o) {
  332. // json
  333. var j = $j.parse(o.responseText);
  334. // msg
  335. if ( j.stat != 1 ) {
  336. alert(j.msg);
  337. }
  338. // update last
  339. $('update-current').innerHTML = "<strong>Latest:</strong> "+o.argument[1];
  340. $('update-txt').value = "";
  341. $('update-chars').innerHTML = 140;
  342. // check timeline
  343. if ( $d.inDocument('status-list') ) {
  344. // add to the dom
  345. var ul = document.createElement('ul');
  346. ul.innerHTML = j.resp.html;
  347. // append to doc
  348. document.body.appendChild(ul);
  349. // get node
  350. var li = ul.getElementsByTagName('li')[0];
  351. // timeline
  352. var tl = $('status-list');
  353. // remoce
  354. $d.removeClass(li.getElementsByClassName('defer'),'defer');
  355. // has child
  356. if ( tl.getElementsByTagName('li').length > 0 ) {
  357. $d.insertBefore(li,tl.getElementsByTagName('li')[0]);
  358. }
  359. else {
  360. tl.appendChild(li);
  361. }
  362. // remove holder
  363. ul.parentNode.removeChild(ul);
  364. }
  365. },
  366. 'argument': [this,update]
  367. };
  368. // url
  369. var url = this.xhrUrl('update');
  370. // pb
  371. var pb = 'status='+encodeURIComponent( update );
  372. // podt
  373. var r = $c.asyncRequest('POST',url,callback,pb);
  374. },
  375. /* doInlineRate */
  376. doInlineRate : function(id,cur) {
  377. // slider
  378. TT.data['slider'+id] = YAHOO.widget.Slider.getHorizSlider("slider-bg-"+id,"slider-thumb-"+id,0,200);
  379. // ger real value
  380. TT.data['slider'+id].getRealValue = function() {
  381. return Math.round(this.getValue() * 1);
  382. }
  383. TT.data['slider'+id].subscribe('change', function (newOffset) {
  384. $("Rate-"+id).innerHTML = TT.data['slider'+id].getRealValue();
  385. });
  386. TT.data['slider'+id+'cur'] = cur;
  387. TT.data['slider'+id].subscribe('slideEnd', function () {
  388. var n = TT.data['slider'+id].getRealValue();
  389. if ( n != TT.data['slider'+id+'cur'] ) {
  390. clearTimeout(TT.data['slider'+id+'TO']);
  391. TT.data['slider'+id+'TO'] = setTimeout(function(){
  392. var callback = {
  393. 'success': function(o) {}
  394. };
  395. var url = TT.Global.xhrUrl('rate',{'id': id});
  396. // go
  397. var r = $c.asyncRequest('POST',url,callback,'n='+n);
  398. },500);
  399. }
  400. });
  401. TT.data['slider'+id].setValue(cur);
  402. },
  403. /* doPic */
  404. doPic : function(tar) {
  405. // blur
  406. tar.blur();
  407. // get some info
  408. var info = tar.id.split('|');
  409. // if already open we should close
  410. if ( $d.hasClass(tar,'open') ) {
  411. $d.removeClass(tar,'open');
  412. $d.setStyle(info[1]+'-wrap','display','none');
  413. tar.innerHTML = "(open pic)";
  414. return;
  415. }
  416. // not open but el exists
  417. else if ( $d.inDocument(info[1]+'-wrap') ) {
  418. $d.setStyle(info[1]+'-wrap','display','block');
  419. $d.addClass(tar,'open');
  420. tar.innerHTML = "(close pic)";
  421. return;
  422. }
  423. // el
  424. var el = $(info[1]);
  425. var url = "";
  426. // twitpic?
  427. if ( el.href.indexOf('twitpic.com') !== -1 ) {
  428. // get the id
  429. var id = /twitpic\.com\/([a-zA-Z0-9]+)/.exec(el.href)[1];
  430. // url
  431. url = "http://twitpic.com/show/large/"+id+".jpg";
  432. }
  433. // new img
  434. var img = new Image();
  435. img.src = url;
  436. // get status
  437. var status = $d.isGoodTarget(tar,'status',10);
  438. // create our warp
  439. var wrap = document.createElement('div');
  440. wrap.id = info[1]+'-wrap';
  441. wrap.className = 'external-wrap';
  442. // add some html
  443. wrap.innerHTML = "<b class='tl'></b><b class='tr'></b><b class='bl'></b><b class='br'></b>" +
  444. "<img src='"+url+"'>";
  445. // append
  446. status.appendChild(wrap);
  447. // show
  448. $d.addClass(tar,'open');
  449. // close
  450. tar.innerHTML = "(close pic)";
  451. },
  452. /* dp video */
  453. doVideo : function(tar) {
  454. // blur
  455. tar.blur();
  456. // get some info
  457. var info = tar.id.split('|');
  458. // if already open we should close
  459. if ( $d.hasClass(tar,'open') ) {
  460. $d.removeClass(tar,'open');
  461. $d.setStyle(info[1]+'-wrap','display','none');
  462. tar.innerHTML = "(open video)";
  463. return;
  464. }
  465. // not open but el exists
  466. else if ( $d.inDocument(info[1]+'-wrap') ) {
  467. $d.setStyle(info[1]+'-wrap','display','block');
  468. $d.addClass(tar,'open');
  469. tar.innerHTML = "(close video)";
  470. return;
  471. }
  472. // el
  473. var el = $(info[1]);
  474. var embed = "";
  475. // twitpic?
  476. if ( el.href.indexOf('youtube.com') !== -1 ) {
  477. var id = /youtube.com\/watch\?v=([a-zA-Z0-9\-\_]+)/.exec(el.href)[1];
  478. // url
  479. embed = '<object width="425" height="344"><param name="movie" value="http://www.youtube.com/v/tX5hQeD71ns&hl=en&fs=1"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/'+id+'&hl=en&fs=1" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"></embed></object>';
  480. }
  481. else if ( el.href.indexOf('qik.com') !== -1 ) {
  482. // we need to set off and get the quick ememb
  483. var callback = {
  484. 'success': function(o) {
  485. // ememb
  486. $(o.argument[1]).innerHTML = "<b class='tl'></b><b class='tr'></b><b class='bl'></b><b class='br'></b>" +
  487. o.responseText;
  488. },
  489. 'argument': [this,info[1]+'-wrap']
  490. };
  491. // url
  492. var url = this.xhrUrl('embed');
  493. // pb
  494. var pb = "url="+escape(el.href);
  495. // go
  496. var r = $c.asyncRequest('POST',url,callback,pb);
  497. // loading
  498. embed = "<span class='loading'>Loading Video...</span>";
  499. }
  500. // get status
  501. var status = $d.isGoodTarget(tar,'status',10);
  502. // create our warp
  503. var wrap = document.createElement('div');
  504. wrap.id = info[1]+'-wrap';
  505. wrap.className = 'external-wrap';
  506. // add some html
  507. wrap.innerHTML = "<b class='tl'></b><b class='tr'></b><b class='bl'></b><b class='br'></b>" +
  508. embed;
  509. // append
  510. status.appendChild(wrap);
  511. // show
  512. $d.addClass(tar,'open');
  513. // close
  514. tar.innerHTML = "(close video)";
  515. },
  516. /* addPreLink */
  517. addPreLink : function(lnks) {
  518. // no list
  519. if ( !this.preLinks ) {
  520. this.preLinks = [];
  521. }
  522. for ( var l in lnks ) {
  523. this.preLinks[this.preLinks.length] = lnks[l];
  524. }
  525. },
  526. /* parseTimelineLinks */
  527. parseTimelineLinks : function() {
  528. // links
  529. var links = this.preLinks;
  530. // none
  531. if ( !links || links.length == 0 ) {
  532. return;
  533. }
  534. // links
  535. TT.data.links = {};
  536. // gorup
  537. var g = [];
  538. var n = Math.ceil( links.length / 3 );
  539. // foreach links
  540. for ( var i = 0; i < n; i++ ) {
  541. var s = i*3;
  542. g[g.length] = links.slice(s,s+3);
  543. }
  544. this.linkGroups = g;
  545. // if g > 0
  546. if ( this.linkGroups.length > 0 ) {
  547. // do the first one now
  548. this.injectLinks(this.linkGroups.shift());
  549. // that
  550. var that = this;
  551. this.linkInterval = window.setInterval(function(){
  552. if ( that.linkGroups.length == 0 ) {
  553. clearInterval(that.linkInterval); return;
  554. }
  555. that.injectLinks(that.linkGroups.shift());
  556. },500);
  557. }
  558. },
  559. // inject linsk
  560. injectLinks : function(item) {
  561. // callback
  562. var callback = {
  563. 'success': function(o) {
  564. // respinse
  565. var j = $j.parse(o.responseText);
  566. // if j
  567. if ( j.stat != 1 ) {
  568. alert(j.msg); return;
  569. }
  570. // lenght
  571. if ( j.resp.length == 0 ) {
  572. return;
  573. }
  574. // foreach of the links
  575. for ( var l in j.resp ) {
  576. // object
  577. var o = j.resp[l];
  578. if ( $d.inDocument(l) ) {
  579. // links
  580. TT.data.links[l] = o;
  581. // always change the source
  582. $(l).href = o.url;
  583. if ( o.type == 'video' ) {
  584. // set url
  585. $(l).innerHTML = o.short;
  586. // exapnd link
  587. $(o.type+'|'+l).innerHTML = "(view video)";
  588. // set it
  589. $d.removeClass(o.type+'|'+l,'hide');
  590. }
  591. else if ( o.type == 'pic' ) {
  592. // set url
  593. $(l).innerHTML = o.short;
  594. // exapnd link
  595. $(o.type+'|'+l).innerHTML = "(view pic)";
  596. // set it
  597. $d.removeClass(o.type+'|'+l,'hide');
  598. }
  599. else {
  600. // show short
  601. $(l).innerHTML = o.short;
  602. // set it
  603. $d.removeClass(o.type+'|'+l,'hide');
  604. // if they're the same remove extend
  605. if ( o.short == o.url ) {
  606. // $(o.type+'|'+l).parentNode.removeChild($(o.type+'|'+l));
  607. }
  608. }
  609. }
  610. }
  611. },
  612. 'argument': [this]
  613. };
  614. // url
  615. var url = this.xhrUrl('links');
  616. // pb
  617. var pb = 'links='+escape( $j.stringify(item) );
  618. // xhr
  619. var r = $c.asyncRequest('POST',url,callback,pb);
  620. },
  621. // fav
  622. doFav : function(tar) {
  623. // blur
  624. tar.blur();
  625. // done
  626. if ( $d.hasClass(tar,'done') ) {
  627. return;
  628. }
  629. // info
  630. var oTar = tar;
  631. var li = $d.isGoodTarget(tar,'status');
  632. // info
  633. var info = li.id.split('|');
  634. // callback
  635. var callback = {
  636. 'success': function(o) {
  637. // r
  638. var r = o.responseText;
  639. // what up
  640. if ( r != 'true' ) {
  641. $d.removeClass(oTar,'saving');
  642. alert(r);
  643. }
  644. else {
  645. $d.removeClass(oTar,'saving');
  646. $d.addClass(oTar,'done');
  647. }
  648. },
  649. 'argument': [this]
  650. };
  651. // url
  652. var url = this.xhrUrl('fav',{'id':info[1]});
  653. // change to new image
  654. $d.addClass(oTar,'saving');
  655. // li on
  656. $d.addClass(li,'on');
  657. // send
  658. var r = $c.asyncRequest('GET',url,callback);
  659. },
  660. // submit reply
  661. submitReply : function(e) {
  662. // callback
  663. var callback = {
  664. 'success': function(o) {
  665. // text
  666. var r = o.responseText;
  667. // hide
  668. o.argument[0].replying = false;
  669. o.argument[0].reply.hide();
  670. // response
  671. if ( r != 'true' ) {
  672. alert(r);
  673. }
  674. },
  675. 'argument': [this]
  676. };
  677. // url
  678. var url = this.xhrUrl('reply');
  679. // post body
  680. var pb = "msg="+encodeURIComponent( $('reply-text').value )+"&to="+this.replying.id;
  681. $d.addClass('reply','saving');
  682. $('reply-submit').disabled = true;
  683. // post
  684. var r = $c.asyncRequest('POST',url,callback,pb);
  685. },
  686. // do reply
  687. doReply : function(tar) {
  688. // get paretn
  689. var li = $d.isGoodTarget(tar,'status');
  690. // no li
  691. if ( !li ) { return; }
  692. // info
  693. var info = li.id.split('|');
  694. // get data
  695. var data = TT.data.tweets[info[1]];
  696. // no data
  697. if ( !data ) { return; }
  698. // sn
  699. var sn = data.user.screen_name;
  700. $('reply-hd').innerHTML = "Reply to "+sn;
  701. $('reply-text').value = "@"+sn + " ";
  702. $('reply-chars').innerHTML = 140 - parseInt(sn.length,10);
  703. $('reply-quote').innerHTML = "<em>"+sn+"</em> " + data.text;
  704. $d.setStyle('reply-chars','color','#555');
  705. $('reply-submit').disabled = false;
  706. $d.removeClass('reply','saving');
  707. // reply
  708. this.replying = data;
  709. // show
  710. this.reply.show();
  711. },
  712. // open
  713. openGroup : function(tar) {
  714. // get info
  715. var info = tar.id.split('|');
  716. // fade the bd
  717. var a = new $a('bd',{opacity:{to:.2}},.5);
  718. a.animate();
  719. // figure where they are
  720. var xy = $d.getXY(tar);
  721. // show
  722. $d.setStyle('Group','display','block');
  723. // move
  724. $d.setXY('Group',[xy[0],xy[1]+20]);
  725. // callback
  726. var callback = {
  727. 'success': function(o) {
  728. // json
  729. var j = $j.parse(o.responseText);
  730. // check resp
  731. if ( j.stat != 1 ) {
  732. alert(j.msg); return;
  733. }
  734. // no longer saving
  735. $d.removeClass('Group','saving');
  736. // get groups
  737. var ul = $('Group').getElementsByTagName('ul')[0].getElementsByTagName('li');
  738. // go for each val
  739. for ( var i = 0; i < ul.length; i++ ) {
  740. var gid = ul[i].className.replace(/group-/,'');
  741. if ( inArray(j.resp,gid) ) {
  742. var box = ul[i].getElementsByTagName('input')[0];
  743. box.checked = true;
  744. }
  745. }
  746. },
  747. 'argument': [this]
  748. };
  749. // groups
  750. this.grouping = info[1];
  751. // xhr
  752. var url = this.xhrUrl('group',{'friend':info[1]});
  753. // go
  754. var r = $c.asyncRequest('GET',url,callback);
  755. },
  756. // do group
  757. doGroup : function(tar) {
  758. // callback
  759. var callback = {
  760. 'success': function(o) {
  761. // bring in
  762. var a = new $a('bd',{opacity:{to:1}},.3);
  763. a.animate();
  764. // take out
  765. $d.setXY('Group',[-999,-999]);
  766. // json
  767. var j = {};
  768. // json
  769. try {
  770. j = $j.parse(o.responseText);
  771. }
  772. catch(e) {
  773. alert("There was an error while adding this friend to group(s). Please try again.");
  774. Triangle("Parse error: "+e+" || "+o.responseText);
  775. return;
  776. }
  777. // check resp
  778. if ( j.stat != 1 ) {
  779. alert(j.msg); return;
  780. }
  781. // get groups
  782. var ul = $('Group').getElementsByTagName('ul')[0].getElementsByTagName('li');
  783. // go for each val
  784. for ( var i = 0; i < ul.length; i++ ) {
  785. var box = ul[i].getElementsByTagName('input')[0];
  786. box.checked = false;
  787. }
  788. },
  789. 'failure': function(o) {
  790. // alert
  791. alert("There was an error adding this friend to a group. Please try again");
  792. // triangle
  793. Triangle("do-rate failed:"+o.statusText);
  794. // bring in
  795. var a = new $a('bd',{opacity:{to:1}},.3);
  796. a.animate();
  797. // take out
  798. $d.setXY('Group',[-999,-999]);
  799. },
  800. 'argument': [this],
  801. 'timeout': 5000
  802. };
  803. // checked
  804. var checked = [];
  805. // get groups
  806. var ul = $('Group').getElementsByTagName('ul')[0].getElementsByTagName('li');
  807. for ( var i = 0; i < ul.length; i++ ) {
  808. var gid = ul[i].className.replace(/group-/,'');
  809. var box = ul[i].getElementsByTagName('input')[0];
  810. if ( box.checked == true ) {
  811. checked[checked.length] = [gid,true];
  812. }
  813. else {
  814. checked[checked.length] = [gid,false];
  815. }
  816. }
  817. // no longer saving
  818. $d.addClass('Group','saving');
  819. // xhr
  820. var url = this.xhrUrl('updategroup',{'friend':this.grouping});
  821. // go
  822. var r = $c.asyncRequest('POST',url,callback,'g='+$j.stringify(checked)+'&u='+escape($j.stringify(TT.data.friends[this.grouping])));
  823. },
  824. // delete group
  825. deleteGroup : function(tar) {
  826. // info
  827. var info = tar.id.split('|');
  828. // ask
  829. var dl = new YAHOO.widget.SimpleDialog("dl",
  830. { width: "300px",
  831. fixedcenter: true,
  832. modal: true,
  833. visible: false,
  834. draggable: false,
  835. close: true,
  836. text: "Are you sure you want to delete this group. There's no way to get it back once you delete?",
  837. icon: YAHOO.widget.SimpleDialog.ICON_HELP,
  838. constraintoviewport: true,
  839. buttons: [ { text:"Yes", handler:function(){ window.location.href = '/groups?do=delete;id='+info[1]; }, isDefault:true },
  840. { text:"No", handler: function() { this.hide(); this.destroy(); } } ]
  841. } );
  842. dl.setHeader("Really?");
  843. dl.render( document.body );
  844. dl.show();
  845. },
  846. // do rate
  847. openRate : function(tar) {
  848. // no slider
  849. if ( !this.slider ) {
  850. // slider
  851. var slider = YAHOO.widget.Slider.getHorizSlider("slider-bg","slider-thumb",0,200);
  852. // ger real value
  853. slider.getRealValue = function() {
  854. return Math.round(this.getValue() * 1);
  855. }
  856. slider.subscribe('change', function (newOffset) {
  857. $("Rate-N").innerHTML = slider.getRealValue()+10;
  858. });
  859. this.slider = slider;
  860. }
  861. // get info
  862. var info = tar.id.split('|');
  863. // fade the bd
  864. var a = new $a('bd',{opacity:{to:.2}},.5);
  865. a.animate();
  866. // figure where they are
  867. var xy = $d.getXY(tar);
  868. // show
  869. $d.setStyle('Rate','display','block');
  870. // set the id
  871. this.rating = info[1];
  872. // move
  873. $d.setXY('Rate',[xy[0],xy[1]+20]);
  874. // check info
  875. if ( this.rated[info[1]] ) {
  876. this.slider.setValue(this.rated[info[1]]);
  877. }
  878. else if ( info[2] != "" ) {
  879. this.slider.setValue( parseInt(info[2],10) );
  880. }
  881. else {
  882. this.slider.setValue(0);
  883. }
  884. },
  885. // open
  886. openTag : function(tar) {
  887. // get info
  888. var info = tar.id.split('|');
  889. // fade the bd
  890. var a = new $a('bd',{opacity:{to:.2}},.5);
  891. a.animate();
  892. // figure where they are
  893. var xy = $d.getXY(tar);
  894. // set
  895. if ( this.tagged[info[1]] ) {
  896. $('Tag-T').value = this.tagged[info[1]];
  897. }
  898. else if ( info[2] ) {
  899. $('Tag-T').value = info[2];
  900. }
  901. else {
  902. $('Tag-T').value = "";
  903. }
  904. // show
  905. $d.setStyle('Tag','display','block');
  906. // set the id
  907. this.tagging = info[1];
  908. // move
  909. $d.setXY('Tag',[xy[0],xy[1]+20]);
  910. },
  911. // do tag
  912. doTag : function(tar) {
  913. // do tag
  914. var tags = $('Tag-T').value;
  915. // callback
  916. var callback = {
  917. 'success': function(o) {
  918. // get json
  919. var j = $j.parse(o.responseText);
  920. // good
  921. if ( j.stat != 1 ) {
  922. alert(j.msg); return;
  923. }
  924. // saved it so ipdated and classes
  925. var els = $d.getElementsByClassName('tag-'+o.argument[2],'span',$('bd'));
  926. // show
  927. for ( var el in els ) {
  928. els[el].innerHTML = "("+o.argument[1].split(',').length+")";
  929. }
  930. // bring in
  931. var a = new $a('bd',{opacity:{to:1}},.3);
  932. a.animate();
  933. // take out
  934. $d.setXY('Tag',[-99,-99]);
  935. // rated
  936. o.argument[0].tagged[o.argument[2]] = o.argument[1];
  937. // no sacing
  938. $d.removeClass('Tag','saving');
  939. },
  940. 'argument': [this,tags,this.tagging]
  941. };
  942. // make a url
  943. var url = this.xhrUrl('tag',{'id':this.tagging});
  944. // saving
  945. $d.addClass('Tag','saving');
  946. // go
  947. var r = $c.asyncRequest('POST',url,callback,"tags="+escape(tags));
  948. },
  949. // do rate
  950. doRate : function(tar) {
  951. // number
  952. var n = this.slider.getValue() + 10;
  953. // callback
  954. var callback = {
  955. 'success': function(o) {
  956. // get json
  957. var j = $j.parse(o.responseText);
  958. // good
  959. if ( j.stat != 1 ) {
  960. alert(j.msg); return;
  961. }
  962. // saved it so ipdated and classes
  963. var els = $d.getElementsByClassName('rate-'+o.argument[2],'span',$('bd'));
  964. // show
  965. for ( var el in els ) {
  966. els[el].innerHTML = "("+o.argument[1]+")";
  967. }
  968. // bring in
  969. var a = new $a('bd',{opacity:{to:1}},.3);
  970. a.animate();
  971. // take out
  972. $d.setXY('Rate',[-99,-99]);
  973. // rated
  974. o.argument[0].rated[o.argument[2]] = o.argument[1];
  975. // no sacing
  976. $d.removeClass('Rate','saving');
  977. },
  978. 'argument': [this,n,this.rating]
  979. };
  980. // make a url
  981. var url = this.xhrUrl('rate',{'id':this.rating});
  982. // saving
  983. $d.addClass('Rate','saving');
  984. // go
  985. var r = $c.asyncRequest('POST',url,callback,"n="+n);
  986. },
  987. // load
  988. loadTimeline : function(p) {
  989. // not in p
  990. var params = {};
  991. for ( var pp in p ) {
  992. if ( pp != 'id' && pp != 'req' && p != 'translate' ) {
  993. params[pp] = p[pp];
  994. }
  995. }
  996. // make our url
  997. // var url = this.xhrUrl('timeline',{'since':p.since,'page':p.page,'tag':p.tag});
  998. var url = this.xhrUrl('timeline',params);
  999. // callback
  1000. var callback = {
  1001. 'success': function(o) {
  1002. // parse json
  1003. var j = $j.parse(o.responseText);
  1004. // if good
  1005. if ( j.stat != 1 ) {
  1006. alert(j.msg); return;
  1007. }
  1008. // just add it
  1009. $(o.argument[1].id).innerHTML = j.resp.html;
  1010. // save data
  1011. TT.data['tweets'] = j.resp.raw;
  1012. // no loading
  1013. $d.removeClass(o.argument[1].id,'loading');
  1014. // remove defer class
  1015. $d.removeClass($d.getElementsByClassName('defer'),'defer');
  1016. // exec
  1017. TT.executeQueue();
  1018. // check for links
  1019. o.argument[0].parseTimelineLinks();
  1020. },
  1021. 'argument': [this,p]
  1022. };
  1023. // go
  1024. var r = $c.asyncRequest('GET',url,callback);
  1025. },
  1026. /**
  1027. * load live timeline
  1028. */
  1029. loadLiveTimeline : function(p) {
  1030. // taht
  1031. var that = this;
  1032. var p = p;
  1033. // need holder
  1034. if ( !$d.inDocument('live-holder') ) {
  1035. var div = document.createElement('div');
  1036. div.id = 'live-holder';
  1037. // style
  1038. $d.setStyle(div,'display','none');
  1039. // append
  1040. $('doc').appendChild(div);
  1041. // hilder
  1042. this.flags.liveHolder = $('live-holder');
  1043. }
  1044. // set timout
  1045. this.liveTimeout = window.setInterval(function(){
  1046. that.doLiveTimeline(p);
  1047. },(1000*60));
  1048. },
  1049. /**
  1050. */
  1051. doLiveTimeline : function(p) {
  1052. // callback
  1053. var callback = {
  1054. 'success': function(o) {
  1055. // parse json
  1056. var j = $j.parse(o.responseText);
  1057. // some arsg
  1058. var t = o.argument[0];
  1059. // if good
  1060. if ( j.stat != 1 ) {
  1061. return;
  1062. }
  1063. // check raw
  1064. if ( j.resp.raw.length == 0 ) {
  1065. return;
  1066. }
  1067. // load into holder
  1068. t.flags.liveHolder.innerHTML = j.resp.html;
  1069. // get list
  1070. var list = $d.getElementsByClassName('status','li',t.flags.liveHolder.getElementsByTagName('ul')[0]);
  1071. // how many
  1072. if ( list.length == 0 ) {
  1073. return;
  1074. }
  1075. // how many divided by a second
  1076. var per = Math.ceil(list.length*1/59);
  1077. // el
  1078. var wrap = $(o.argument[1].id);
  1079. // make sure the ul lis ther
  1080. if ( wrap.getElementsByTagName('ul').length != 1 ) {
  1081. var ul = document.createElement('ul');
  1082. ul.className = 'timeline';
  1083. wrap.innerHTML = "";
  1084. wrap.appendChild(ul);
  1085. }
  1086. // el
  1087. var el = wrap.getElementsByTagName('ul')[0];
  1088. // everyone?
  1089. var interval = 1000;
  1090. if ( o.argument[1]['for'] == 'everyone' ) {
  1091. interval = 3000;
  1092. per = 1;
  1093. }
  1094. // start our loop
  1095. t.liveLoop = setInterval(function(){
  1096. // is holder temp
  1097. if ( list.length == 0 ) {
  1098. clearInterval(t.liveLoop);
  1099. }
  1100. else if ( list.length < per ) {
  1101. per = list.length;
  1102. }
  1103. // else for how many we add
  1104. for ( var i = 0; i < per; i++ ) {
  1105. // giver a try
  1106. try {
  1107. // set the opacity of the list item
  1108. var e = list[list.length-1];
  1109. // opacity
  1110. $d.setStyle(e,'opacity',0);
  1111. var cur = el.getElementsByTagName('li').length;
  1112. // insert to top of list
  1113. if ( cur == 0 ) {
  1114. el.appendChild(e);
  1115. }
  1116. else {
  1117. $d.insertBefore(e,el.firstChild);
  1118. }
  1119. // fade in
  1120. var a = new $a(e,{'opacity':{'to':1}},.4);
  1121. a.animate();
  1122. // pop the last off the list
  1123. if ( cur >= 20 ) {
  1124. el.removeChild(el.lastChild);
  1125. }
  1126. }
  1127. catch(e) {}
  1128. }
  1129. },interval);
  1130. // up the counter
  1131. o.argument[0].flags.liveCounter++;
  1132. },
  1133. 'argument': [this,p]
  1134. };
  1135. clearInterval(this.liveLoop);
  1136. // make our url
  1137. var params = {'since':p.since,'pager':false};
  1138. // no live if first`
  1139. params['live'] = true;
  1140. // make our url
  1141. var url = this.xhrUrl('timeline',params);
  1142. // go
  1143. var r = $c.asyncRequest('GET',url,callback);
  1144. },
  1145. /**
  1146. */
  1147. destroyLiveTimeout : function() {
  1148. clearInterval(this.liveTimeout);
  1149. clearInterval(this.liveLoop);
  1150. },
  1151. /**
  1152. * load xhr page
  1153. */
  1154. loadXhrPage : function(href,history) {
  1155. // reg
  1156. var reg = false;
  1157. // regex
  1158. if ( location.href.indexOf('https:') !== -1 ) {
  1159. reg = new RegExp("https:\/\/(www\.|networks\.|api\.)?twittangle\.com");
  1160. }
  1161. else {
  1162. reg = new RegExp("http:\/\/(www\.|networks\.|api\.)?twittangle\.com");
  1163. }
  1164. // typeof
  1165. if ( typeof href.match(reg)[1] == 'undefined' ) {
  1166. window.location.href = href; return;
  1167. }
  1168. // sub
  1169. var subdomain = href.match(reg)[1].replace(/\./,'');
  1170. // check it out
  1171. if ( href.match(reg)[1] != location.href.match(reg)[1] ) {
  1172. location.href = href; return
  1173. }
  1174. // lets check to see if the
  1175. // url is the right subdomain
  1176. if ( !href.match(reg) || href.indexOf('#') != -1 ) {
  1177. return;
  1178. }
  1179. // abort last call
  1180. if ( this.lastXhrPageReq ) {
  1181. $c.abort(this.lastXhrPageReq);
  1182. }
  1183. // get the page
  1184. var rx = new RegExp("http(s)?:\/\/(www\.|networks\.|api\.)?twittangle\.com\/",'gi');
  1185. // figure the page
  1186. var page = href.replace(rx,'');
  1187. // no page
  1188. if ( page == "" || page == 'login' || page == 'logout' || page == 'start' ) {
  1189. location.href = href; return;
  1190. }
  1191. // parse out qp
  1192. var path = page.split('?')[0];
  1193. // is there a query
  1194. if ( page.indexOf('?') != -1 ) {
  1195. var query = page.split('?')[1].split(';');
  1196. }
  1197. // now get params
  1198. var params = {};
  1199. // for each
  1200. for ( var q in query ) {
  1201. params[query[q].split('=')[0]] = encodeURI(query[q].split('=')[1]);
  1202. }
  1203. // now define our callback
  1204. var callback = {
  1205. 'success': function(o) {
  1206. // j
  1207. var j;
  1208. // try to parse. if we fail
  1209. // we just redirect to the proper page
  1210. try {
  1211. j = $j.parse(o.responseText);
  1212. }
  1213. catch(e) {
  1214. window.location.href = o.argument[1]; return;
  1215. }
  1216. // if theres a bad stat
  1217. // we need to stop
  1218. if ( j.stat != 1 ) {
  1219. window.location.href = o.argument[1]; return;
  1220. }
  1221. // set class name and title
  1222. document.getElementsByTagName('body')[0].className = j.c + ' yui-skin-sam';
  1223. document.title = j.t;
  1224. // r
  1225. if ( j.r ) {
  1226. if ( $d.inDocument('rsslink') ) {
  1227. $('rsslink').href = j.r;
  1228. }
  1229. else {
  1230. var l = document.createElement('link');
  1231. l.setAttribute('rel','alternate');
  1232. l.href = j.r
  1233. l.setAttribute('type','application/rss+xml');
  1234. l.setAttribute('title','twitTangle.com');
  1235. l.id = 'rsslink';
  1236. document.getElementsByTagName('head')[0].appendChild(l);
  1237. }
  1238. }
  1239. else if ( $d.inDocument('rsslink') ) {
  1240. $('rsslink').parentNode.removeChild($('rsslink'))
  1241. }
  1242. if ( $d.inDocument('rateLimit') ) {
  1243. $('rateLimit').innerHTML = j.l;
  1244. }
  1245. // remove any set event handlers
  1246. $e.purgeElement( $('bd'), true );
  1247. // set the body
  1248. $('Content').innerHTML = j.html;
  1249. // bootstrap
  1250. o.argument[0].bootstrap(j.bootstrap);
  1251. // scroll
  1252. window.scrollTo(0,0);
  1253. // done loading
  1254. $l(0);
  1255. // no bubble
  1256. $d.setXY( $('title-bubble') ,[-999,-999]);
  1257. // remove
  1258. if ( $d.inDocument('customStyle') ) {
  1259. $('customStyle').parentNode.removeChild($('customStyle'));
  1260. }
  1261. // remove defer class
  1262. $d.removeClass($d.getElementsByClassName('defer'),'defer');
  1263. // new
  1264. if ( j.p ) {
  1265. try {
  1266. var s = document.createElement('style');
  1267. s.setAttribute('type','text/css');
  1268. s.id = 'customStyle';
  1269. if ( s.styleSheet ) {
  1270. s.styleSheet.cssText = j.p;
  1271. }
  1272. else {
  1273. s.innerHTML = j.p;
  1274. }
  1275. // append
  1276. document.getElementsByTagName('head')[0].appendChild(s);
  1277. } catch(e) {}
  1278. }
  1279. // get height of content
  1280. var ch = parseInt($d.getStyle('Content','height'),10);
  1281. var mh = parseInt($d.getStyle('yui-main','height'),10);
  1282. // check main
  1283. if ( mh < ch ) {
  1284. // get b
  1285. var el = $d.getElementsByClassName('yui-b','div',$('yui-main'))[0];
  1286. if ( el ) {
  1287. $d.setStyle(el,'height',ch+'px');
  1288. }
  1289. }
  1290. },
  1291. 'failure' : function(o) {
  1292. window.location.href = o.argument[1]; return;
  1293. },
  1294. 'argument': [this,href],
  1295. 'timeout': 5000
  1296. };
  1297. // unload
  1298. TT.executeUnLoadQueue();
  1299. this.preLinks = null;
  1300. this.linkGroups = [];
  1301. // now build our url
  1302. var url = this.xhrUrl('context/'+path,params);
  1303. // no bubble
  1304. $d.setXY( $('title-bubble') ,[-999,-999]);
  1305. // loading
  1306. $l(1);
  1307. // history
  1308. try {
  1309. if (!history || !history.calledFromHistory) {
  1310. dsHistory.setQueryVar('p', page);
  1311. dsHistory.bindQueryVars(this.loadXhrPage, this, 'http://'+subdomain+'.twittangle.com/'+page);
  1312. }
  1313. } catch(e) {}
  1314. // track
  1315. pageTracker._trackPageview(page);
  1316. // make the request
  1317. this.lastXhrPageReq = $c.asyncRequest('GET',url,callback);
  1318. },
  1319. /**
  1320. * bootstrap javascript
  1321. */
  1322. bootstrap : function(data) {
  1323. // check for bootstrap
  1324. if ( data.js ) {
  1325. // print out each block of javacript
  1326. for ( var s in data.js ) {
  1327. eval(data.js[s]);
  1328. }
  1329. }
  1330. // execute the queue
  1331. TT.executeQueue();
  1332. },
  1333. // xhr
  1334. xhrUrl : function(act,args) {
  1335. // qs
  1336. var qs = ['req='+this.params.req];
  1337. // develope qs
  1338. for ( arg in args ) {
  1339. if ( typeof arg == 'string' ) {
  1340. qs[qs.length] = arg + '=' + args[arg];
  1341. }
  1342. }
  1343. // return it
  1344. return '/xhr/' + act + '?' + qs.join(';');
  1345. }
  1346. }
  1347. // })();
  1348. /* Triangle */
  1349. var Triangle = function(m) { $('triangle').src = '/triangle.php?m='+escape(m); }
  1350. /*!
  1351. * dsHistory, v1-beta1 $Rev: 70 $
  1352. * Revision date: $Date: 2008-10-24 14:25:17 -0700 (Fri, 24 Oct 2008) $
  1353. * Project URL: http://code.google.com/p/dshistory/
  1354. *
  1355. * Copyright (c) Andrew Mattie (http://www.akmattie.net)
  1356. * Licensed under the MIT License (http://www.opensource.org/licenses/mit-license.php)
  1357. * THIS IS FREE SOFTWARE, BUT DO NOT REMOVE THIS COMMENT BLOCK
  1358. */
  1359. var dsHistory = function() {
  1360. // we need a good browser detection library. these detections were kindly borrowed from the Prototype library
  1361. var browser = (function() {
  1362. var userAgent = window.navigator.userAgent;
  1363. var isIE = !!(window.attachEvent && !window.opera); // may want to rethink this in light of http://ejohn.org/blog/bad-object-detection/
  1364. return {
  1365. IE: isIE,
  1366. IE6: isIE && userAgent.indexOf('MSIE 6') != -1,
  1367. IE7: isIE && userAgent.indexOf('MSIE 7') != -1,
  1368. Opera: !!window.opera && userAgent.indexOf('Opera'),
  1369. WebKit: userAgent.indexOf('AppleWebKit/') > -1,
  1370. Gecko: userAgent.indexOf('Gecko') > -1 && userAgent.indexOf('KHTML') == -1
  1371. };
  1372. })();
  1373. var supportsChangingHistoryViaFrame = browser.IE || browser.Gecko;
  1374. var supportsDataProtocol = browser.Gecko; // other browsers may support the data protocol, but if they don't support changing the history via a frame, they aren't in here
  1375. var returnsEncodedWindowHash = browser.IE || browser.WebKit; // some browsers return the encoded value of the window hash vs the decoded value
  1376. var fluxCapacitorInterval = 15;
  1377. var lastFrameIteration = 0;
  1378. var lastHash = lastRawHash = '';
  1379. var encodeURIComponent = window.encodeURIComponent; // close a reference to this function since we'll be calling it so often and since it will be faster than going up the scope each time
  1380. var dirtyHash = initialHash = getEncodedWindowHash(true);
  1381. var hashCache = []; // holds all previous hashes
  1382. var forwardHashCache = []; // hashes that are removed from hashCache as the user goes back are concat'd here
  1383. var eventCache = []; // holds all events
  1384. var forwardEventCache = []; // events that are removed from eventCache as the user goes back are concat'd here
  1385. var isInHistory = false; // if we're somewhere in the middle of the history stack, this will be set to true
  1386. var frameWindow; // since we're going to be looking at the internals of the frame so often, we will cache a reference to it and just unload it when the page unloads
  1387. // if the reference to this script file is included in the head tag, frameWindow won't be set up properly. this will be a reference to the setInterval that will ultimately set up frameWindow in that case
  1388. var frameWindowWatcher;
  1389. var executionQueue = []; // if the frameWindow wasn't set up on load, we need a place to queue up actions until it's available
  1390. var watcherInterval; // save the handle returned by setInterval so we can unregister it on unload
  1391. var isGoingBackward, isGoingForward; // assists us in knowing whether we're going back through the history or forward
  1392. var usingStringIndicators = false; // if the developer called dsHistory.setUsingStringIndicators(), this will be set to true
  1393. var returnObject;
  1394. // internal function to make sure we don't leave any memory leaks when the visitor leaves
  1395. function unload() {
  1396. window.clearInterval(watcherInterval);
  1397. frameWindow = null;
  1398. eventCache = null;
  1399. };
  1400. // internal function to curry the scope argument and object argument (if either) so that the subscriber can be called once it's appropriately hit in the
  1401. // history
  1402. function internalCurry(fnc, scope, objectArg) {
  1403. if (typeof objectArg != 'undefined') {
  1404. return function(historyObj) {
  1405. fnc.call(scope || window, objectArg, historyObj);
  1406. };
  1407. } else {
  1408. return function(historyObj) {
  1409. fnc.call(scope || window, historyObj);
  1410. };
  1411. }
  1412. };
  1413. // internal function to return the iteration we are on
  1414. function readIteration() {
  1415. // lazy function definition pattern used for performance
  1416. if (!supportsChangingHistoryViaFrame) {
  1417. readIteration = function() {
  1418. return 0;
  1419. };
  1420. } else if (supportsDataProtocol) {
  1421. readIteration = function() {
  1422. return frameWindow.document.body ? parseInt(frameWindow.document.body.textContent) : 0;
  1423. };
  1424. } else {
  1425. readIteration = function() {
  1426. return parseInt(frameWindow.document.body.innerText);
  1427. };
  1428. }
  1429. return readIteration();
  1430. };
  1431. // internal function to save the iteration we are on
  1432. function writeIteration(iteration) {
  1433. // lazy function definition pattern used for performance
  1434. if (supportsDataProtocol) {
  1435. writeIteration = function(iteration) {
  1436. frameWindow.document.body.textContent = String(iteration);
  1437. };
  1438. } else {
  1439. writeIteration = function(iteration) {
  1440. frameWindow.document.body.innerText = String(iteration);
  1441. };
  1442. }
  1443. writeIteration(iteration);
  1444. };
  1445. // internal function to get the decoded value of a (sub)string from the hash
  1446. function getDecodedHashValue(value) {
  1447. if (returnsEncodedWindowHash) {
  1448. var decodeURIComponent = window.decodeURIComponent;
  1449. getDecodedHashValue = function(value) {
  1450. return decodeURIComponent(value);
  1451. };
  1452. } else {
  1453. getDecodedHashValue = function(value) {
  1454. return value;
  1455. };
  1456. }
  1457. return getDecodedHashValue(value);
  1458. };
  1459. // internal function to return the window hash after the keys and values have been run through encodeURIComponent
  1460. function getEncodedWindowHash(forceRecompute) {
  1461. var hash = window.location.hash;
  1462. // there's no need to go through this function again if the hash that was read out (encoded or decoded, doesn't matter) is the same hash that was read out last time.
  1463. // whenever lastHash is set, it's set to the return value of the function
  1464. if (!forceRecompute && hash == lastRawHash) return lastHash;
  1465. lastRawHash = hash;
  1466. var hashItems = hash.substring(1).split('&');
  1467. var encodedHash;
  1468. // for performance, we'll assume that if we're doing more than 9 concats that it will be quicker to use and array and then use the .join('&') trick
  1469. if (hashItems.length > 9) {
  1470. var encodedHashItems = [];
  1471. for (var i = 0, len = hashItems.length; i < len; ++i) {
  1472. hashSplit = hashItems[i].split('=');
  1473. encodedHashItems.push(encodeURIComponent(getDecodedHashValue(hashSplit[0])) + (hashSplit.length == 2 ? '=' + encodeURIComponent(getDecodedHashValue(hashSplit[1])) : ''));
  1474. }
  1475. encodedHash = encodedHashItems.join('&');
  1476. } else {
  1477. encodedHash = ''
  1478. for (var i = 0, len = hashItems.length; i < len; ++i) {
  1479. hashSplit = hashItems[i].split('=');
  1480. encodedHash += (i == 0 ? '' : '&') + encodeURIComponent(getDecodedHashValue(hashSplit[0])) + (hashSplit.length == 2 ? '=' + encodeURIComponent(getDecodedHashValue(hashSplit[1])) : '');
  1481. }
  1482. }
  1483. return encodedHash;
  1484. };
  1485. // internal function to load and split our query vars into our QueryElements object
  1486. function loadQueryVars() {
  1487. // flush out the object each time this is called
  1488. returnObject.QueryElements = {};
  1489. if (window.location.hash == '' || window.location.hash == '#') return;
  1490. var hashItems = window.location.hash.substring(1).split('&');
  1491. var hashSplit;
  1492. for (i = 0, len = hashItems.length; i < len; ++i) {
  1493. hashSplit = hashItems[i].split('=');
  1494. returnObject.QueryElements[getDecodedHashValue(hashSplit[0])] = hashSplit.length == 2 ? getDecodedHashValue(hashSplit[1]) : '';
  1495. }
  1496. lastHash = getEncodedWindowHash(true);
  1497. };
  1498. // internal function to be called when we want to actually add something to the browser's history
  1499. function updateFrameIteration(comingFromQueryBind) {
  1500. var currentIteration = supportsChangingHistoryViaFrame ? readIteration() : 0;
  1501. var lastEvent, newEvent;
  1502. // it seems that gecko has a sweet bug / feature / something that prevents the history from changing with a frame iteration after a hash has changed the history
  1503. // therefore, we have to mess with the hash enough to get it to add to the browser's history and then change it back so we don't screw up any values in the hash
  1504. if ( (hashCache.length > 0 && browser.Gecko) || browser.WebKit || (!supportsChangingHistoryViaFrame && readIteration() > 0) ) {
  1505. // since it's not IE, and since other browsers don't seem to have a performance problem with setting the window hash when there are lots of
  1506. // elements on a page, we're not going to worry about handling the defer processing attribute here
  1507. if (lastHash == '' && hashCache.length > 1) {
  1508. window.location.hash = '_'; // this can be anything, as long as the hash changes
  1509. lastHash = getEncodedWindowHash(true);
  1510. hashCache.push(lastHash);
  1511. } else if (lastHash != '' || browser.WebKit) {
  1512. // splice the event off the stack so we can add it on later
  1513. lastEvent = eventCache.splice(eventCache.length - 1, 1)[0];
  1514. window.location.hash = lastHash + String(hashCache.length); // this can be anything, as long as the hash changes
  1515. hashCache.push(lastHash + String(hashCache.length));
  1516. // lastHash should only be empty if the browser is WebKit.
  1517. window.location.hash = lastHash == ''

Large files files are truncated, but you can click here to view the full file