LJSUP-7813: New thread expander in S2, minimalism
[livejournal.git] / htdocs / js / thread_expander.ex.js
blobe192fe3cd9fa548a6e1d2e66ac8ff21015c9df33
1 /*
2  * ExpanderEx object is used in s1 style comment pages and provides
3  * ajax functionality to expand comments instead of loading iframe page as it is
4  * in old Expander
5  * expander object is also used in commentmanage.js
6  */
7 ExpanderEx = function(){
8     this.__caller__;    // <a> HTML element from where ExpanderEx was called
9     this.url;           // full url of thread to be expanded
10     this.id;            // id of the thread
11     this.stored_caller;
12     this.is_S1;         // bool flag, true == journal is in S1, false == in S2
14 ExpanderEx.Collection={};
15 ExpanderEx.ReqCache = {};
17 ExpanderEx.make = function(el,url,id,is_S1){
18     var local = (new ExpanderEx).set({__caller__:el,url:url.replace(/#.*$/,''),id:id,is_S1:!!is_S1});
19     local.get();
22 ExpanderEx.collapse = function(el,url,id,is_S1){
23     var local = (new ExpanderEx).set({__caller__:el,url:url.replace(/#.*$/,''),id:id,is_S1:!!is_S1});
24     local.collapseThread();
27 ExpanderEx.prototype.set = function(options){
28     for(var opt in options){
29         this[opt] = options[opt];
30     }
31     return this;
34 ExpanderEx.prototype.getCanvas = function(id,context){
35     return context.document.getElementById('ljcmt'+id);
38 ExpanderEx.prototype.parseLJ_cmtinfo = function(context,callback){
39     var map={}, node, j;
40     var LJ = context.LJ_cmtinfo;
41     if(!LJ)return false;
42     for(j in LJ){
43         if(/^\d*$/.test(j) && (node = this.getCanvas(j,context))){
44             map[j] = {info:LJ[j],canvas:node};
45             if(typeof callback == 'function'){
46                 callback(j,map[j]);
47             }
48         }
49     }
50     return map;
53 ExpanderEx.preloadImg = function(){
54     (new Image()).src = Site.imgprefix + '/preloader-s.gif?v=3';
57 ExpanderEx.prototype.addPreloader = function(){
58     this.loader = new Image();
59     this.loader.src = Site.imgprefix + '/preloader-s.gif?v=3';
60     this.loader.className = 'i-exp-preloader';
61     this.__caller__.parentNode.appendChild( this.loader );
64 ExpanderEx.prototype.removePreloader = function(){
65     if( !this.loader ){
66         return;
67     }
69     if( this.loader.parentNode ){
70         this.loader.parentNode.removeChild( this.loader );
71     }
72     delete this.loader;
75 ExpanderEx.prototype.loadingStateOn = function(){
76     // turn on preloader there
77     this.addPreloader();
78     this.stored_caller = this.__caller__.cloneNode(true);
79     this.__caller__.setAttribute('already_clicked','already_clicked');
80     this.__caller__.onclick = function(){return false}
81     this.__caller__.style.color = '#ccc';
84 ExpanderEx.prototype.loadingStateOff = function(){
85     if(this.__caller__){
86         // actually, the <a> element is removed from main window by
87         // copying comment from ifame, so this code is not executed (?)
88         this.__caller__.removeAttribute('already_clicked','already_clicked');
89         if(this.__caller__.parentNode) this.__caller__.parentNode.replaceChild(this.stored_caller,this.__caller__);
90         //remove preloader if exist
91         this.removePreloader();
92     }
93     var obj = this;
94     // When frame is removed immediately, IE raises an error sometimes
97 ExpanderEx.prototype.killFrame = function(){
98     document.body.removeChild(this.iframe);
101 ExpanderEx.prototype.isFullComment = function( comment ) {
102     return !!Number(comment.info.full);
105 ExpanderEx.prototype.expandThread = function( json ) {
106     this.loadingStateOff();
108     //we show expand link if comment block has collapsed children
109     function isChildCollapsed( idx )
110     {
111         var state;
112         for( var i = idx + 1; i < json.length; ++i ) {
113             state = json[ i ].state;
114             if( state === "expanded" ) { return false; }
115             if( state === "collapsed" ) { return true; }
116         }
118         return  false;
119     }
121     var threadId, cell;
122     for( var i = 0; i < json.length; ++i ) {
123         //we skip comment blocks thate were not expanded
124         if( json[ i ].state && json[ i ].state !== "expanded") {
125             continue;
126         }
128         threadId = json[ i ].thread;
130         var oldHtml = LiveJournal.CommentManager.updateCell( threadId, json[ i ].html );
131         if( !( threadId in ExpanderEx.Collection ) ) {
132             ExpanderEx.Collection[ threadId ] = oldHtml;
133         }
134     }
136     //duplicate cycle, because we do not know, that external scripts do with node
137     for( var i = 0; i < json.length; ++i ) {
138         threadId = json[ i ].thread;
139         LJ_cmtinfo[ threadId ].parent = this.id;
140         if( json[ i ].state && json[ i ].state === "expanded") {
141             this.initCommentBlock( jQuery( '#ljcmt' + threadId )[0] , threadId );
142         }
143     }
145     return true;
148 ExpanderEx.prototype.collapseThread = function( id ){
149     var threadId = id || this.id;
150     this.collapseBlock( threadId );
152     var children = LJ_cmtinfo[ threadId ].rc;
153     for( var i = 0; i < children.length; ++i )
154         this.collapseThread( children[ i ] );
157 ExpanderEx.prototype.collapseBlock =  function( id )
159         if( id in ExpanderEx.Collection ) {
160                 LiveJournal.CommentManager.updateCell( id, ExpanderEx.Collection[ id ] );
162                 this.initCommentBlock( LiveJournal.CommentManager.getCell( id )[0], id, true );
163                 delete ExpanderEx.Collection[ id ];
164         }
167 ExpanderEx.prototype.initCommentBlock = function( el_, id, restoreInitState )
169     if( !restoreInitState ){
170         LJ_cmtinfo[ id ].oldvars = {
171             full: LJ_cmtinfo[ id ].full || 0,
172             expanded: LJ_cmtinfo[ id ].expanded || 0
173         }
174         LJ_cmtinfo[ id ].full = 1;
175         LJ_cmtinfo[ id ].expanded = 1;
176     }
177     else {
178         LJ_cmtinfo[ id ].full = LJ_cmtinfo[ id ].oldvars.full;
179         LJ_cmtinfo[ id ].expanded = LJ_cmtinfo[ id ].oldvars.expanded;
180         delete LJ_cmtinfo[ id ].oldvars;
181     }
182     window.ContextualPopup && ContextualPopup.searchAndAdd(el_);
183     //window.setupAjax && setupAjax(el_, true);
184     window.ESN && ESN.initTrackBtns(el_);
188 //just for debugging
189 ExpanderEx.prototype.toString = function(){
190     return '__'+this.id+'__';
194 ExpanderEx.prototype.get = function(){
195     if(this.__caller__.getAttribute('already_clicked')){
196         return false;
197     }
198     this.loadingStateOn();
200     var obj = this;
201     //set timeout to allow browser to display image before request
202     setTimeout( function(){
203         LiveJournal.CommentManager.getThreadJSON( obj.id, function(result) {
204             obj.expandThread(result);
205             ExpanderEx.ReqCache[ obj.id ] = result;
206         }, false, false, true );
207     }, 0 );
209     return true;
212 ExpanderEx.preloadImg();