src/cm/media/js/client/c_db.js
changeset 341 053551f213fb
parent 333 f080de4cad76
child 413 2479d33898dd
equal deleted inserted replaced
340:9e2b9e568e42 341:053551f213fb
     1 Db = function() {
     1 Db = function() {
     2 	//initial comment db as objs (TREE LIKE MODEL : replies are included in comment.replies)
     2   //initial comment db as objs (TREE LIKE MODEL : replies are included in comment.replies)
     3 	this.comments = null; // current set of (filtered) comments 
     3   this.comments = null; // current set of (filtered) comments 
     4 	this.allComments = null; // all server database comments
     4   this.allComments = null; // all server database comments
     5 
     5 
     6 	// obj
     6   // obj
     7 	// keys : commentDbId as string	
     7   // keys : commentDbId as string 
     8 	// values : comment db as obj
     8   // values : comment db as obj
     9 	this.commentsByDbId = {};
     9   this.commentsByDbId = {};
    10 	this.allCommentsByDbId = {};
    10   this.allCommentsByDbId = {};
    11 	
    11   
    12 	// dictionary (always contains all comments (no reply) whatever the filter
    12   // dictionary (always contains all comments (no reply) whatever the filter
    13 	// order key --> ordered array of comment ids (no reply)
    13   // order key --> ordered array of comment ids (no reply)
    14 	this.ordered_comment_ids = {}; // all server database comments
    14   this.ordered_comment_ids = {}; // all server database comments
    15 	
    15   
    16 }
    16 }
    17 
    17 
    18 Db.prototype = {
    18 Db.prototype = {
    19 		
    19     
    20 //////////////////////////////
    20 //////////////////////////////
    21 //		CORE FUNCTIONS
    21 //    CORE FUNCTIONS
    22 //////////////////////////////
    22 //////////////////////////////
    23 	init : function() {
    23   init : function() {
    24 		// at first server side ordered comment by asc ids, replies by creation date :
    24     // at first server side ordered comment by asc ids, replies by creation date :
    25 		this.allComments = CY.JSON.parse(sv_comments) ;
    25     this.allComments = CY.JSON.parse(sv_comments) ;
    26 		if (sv_read_only) {
    26     if (sv_read_only) {
    27 			this.initToReadOnly() ;
    27       this.initToReadOnly() ;
    28 		}
    28     }
    29 		
    29     
    30 	    this._computeAllCommentsByDbId() ;
    30       this._computeAllCommentsByDbId() ;
    31 	    
    31       
    32 	    this._reorder() ;
    32       this._reorder() ;
    33 	},
    33   },
    34 	
    34   
    35 	_del : function (arr, dic, id) {
    35   _del : function (arr, dic, id) {
    36 		// first recursively remove all replies
    36     // first recursively remove all replies
    37 		var comment = dic[id] ;
    37     var comment = dic[id] ;
    38 		
    38     
    39 		for (var i = 0 ; i < comment.replies.length ; i++) {
    39     for (var i = 0 ; i < comment.replies.length ; i++) {
    40 			var rid = comment.replies[i].id ;
    40       var rid = comment.replies[i].id ;
    41 			this._del(comment.replies, dic, rid) ;
    41       this._del(comment.replies, dic, rid) ;
    42 			i--;
    42       i--;
    43 		}
    43     }
    44 		
    44     
    45 		for (var i = 0, ilen = arr.length ; i < ilen ; i++) {
    45     for (var i = 0, ilen = arr.length ; i < ilen ; i++) {
    46 			if (arr[i].id == id) {
    46       if (arr[i].id == id) {
    47 				arr.splice(i, 1) ;
    47         arr.splice(i, 1) ;
    48 				delete dic[id] ;
    48         delete dic[id] ;
    49 				break ;
    49         break ;
    50 			}
    50       }
    51 		}
    51     }
    52 	},
    52   },
    53 
    53 
    54 	del : function(comment) {
    54   del : function(comment) {
    55 		var arr = (comment.reply_to_id == null) ? this.comments : this.commentsByDbId[comment.reply_to_id].replies ; 
    55     var arr = (comment.reply_to_id == null) ? this.comments : this.commentsByDbId[comment.reply_to_id].replies ; 
    56 		this._del(arr, this.commentsByDbId, comment.id) ;
    56     this._del(arr, this.commentsByDbId, comment.id) ;
    57 		arr = (comment.reply_to_id == null) ? this.allComments : this.allCommentsByDbId[comment.reply_to_id].replies ; 
    57     arr = (comment.reply_to_id == null) ? this.allComments : this.allCommentsByDbId[comment.reply_to_id].replies ; 
    58 		this._del(arr, this.allCommentsByDbId, comment.id) ;
    58     this._del(arr, this.allCommentsByDbId, comment.id) ;
    59 		
    59     
    60 		this._reorder() ;
    60     this._reorder() ;
    61 		
    61     
    62 	},
    62   },
    63 	
    63   
    64 	// maintains the ordered lists
    64   // maintains the ordered lists
    65 	_reorder : function() {
    65   _reorder : function() {
    66 		
    66     
    67 		// scope (order by start_wrapper, start_offset, end_wrapper, end_offset 
    67     // scope (order by start_wrapper, start_offset, end_wrapper, end_offset 
    68 		var a = [] ;
    68     var a = [] ;
    69 	    
    69       
    70 		for (var i = 0, ilen = this.allComments.length ; i < ilen ; i++) {
    70     for (var i = 0, ilen = this.allComments.length ; i < ilen ; i++) {
    71 			
    71       
    72 			var comment = this.allComments[i] ;
    72       var comment = this.allComments[i] ;
    73 			var found = false ;
    73       var found = false ;
    74 
    74 
    75 			for (var j = 0, jlen = a.length ; j < jlen ; j++) {
    75       for (var j = 0, jlen = a.length ; j < jlen ; j++) {
    76 				
    76         
    77 				var id = a[j] ;
    77         var id = a[j] ;
    78 				var comment2 = this.allCommentsByDbId[id] ;
    78         var comment2 = this.allCommentsByDbId[id] ;
    79 				
    79         
    80 				if ((comment.start_wrapper < comment2.start_wrapper)
    80         if ((comment.start_wrapper < comment2.start_wrapper)
    81 					||
    81           ||
    82 					((comment.start_wrapper == comment2.start_wrapper) && (comment.start_offset < comment2.start_offset) )
    82           ((comment.start_wrapper == comment2.start_wrapper) && (comment.start_offset < comment2.start_offset) )
    83 					||
    83           ||
    84 					((comment.start_wrapper == comment2.start_wrapper) && (comment.start_offset == comment2.start_offset) && (comment.end_wrapper < comment2.end_wrapper) ) 
    84           ((comment.start_wrapper == comment2.start_wrapper) && (comment.start_offset == comment2.start_offset) && (comment.end_wrapper < comment2.end_wrapper) ) 
    85 					||
    85           ||
    86 					((comment.start_wrapper == comment2.start_wrapper) && (comment.start_offset == comment2.start_offset) && (comment.end_wrapper == comment2.end_wrapper) && (comment.end_offset < comment2.end_offset) ) ) {
    86           ((comment.start_wrapper == comment2.start_wrapper) && (comment.start_offset == comment2.start_offset) && (comment.end_wrapper == comment2.end_wrapper) && (comment.end_offset < comment2.end_offset) ) ) {
    87 						a.splice(j, 0, comment.id) ;
    87             a.splice(j, 0, comment.id) ;
    88 						found = true ;
    88             found = true ;
    89 						break ;
    89             break ;
    90 					}
    90           }
    91 			}
    91       }
    92 			if (!found)  {
    92       if (!found)  {
    93 				a.push(comment.id) ;
    93         a.push(comment.id) ;
    94 			}
    94       }
    95 		}
    95     }
    96 		this.ordered_comment_ids['scope']  = a ;
    96     this.ordered_comment_ids['scope']  = a ;
    97 		
    97     
    98 		// modified thread  
    98     // modified thread  
    99 		a = [] ;
    99     a = [] ;
   100 		var mod = {} ; // we'll aggregate modification dates in this assoc array id --> latest modification
   100     var mod = {} ; // we'll aggregate modification dates in this assoc array id --> latest modification
   101 	    
   101       
   102 		for (var i = 0, ilen = this.allComments.length ; i < ilen ; i++) {
   102     for (var i = 0, ilen = this.allComments.length ; i < ilen ; i++) {
   103 			
   103       
   104 			var comment = this.allComments[i] ;
   104       var comment = this.allComments[i] ;
   105 			var commentModif = comment.modified ;
   105       var commentModif = comment.modified ;
   106 			
   106       
   107       mod[comment.id] = this._latest_mod(comment);
   107       mod[comment.id] = this._latest_mod(comment);
   108 		}
   108     }
   109 		
   109     
   110 		for (var id in mod) {
   110     for (var id in mod) {
   111 			var numberId = this.allCommentsByDbId[id].id			
   111       var numberId = this.allCommentsByDbId[id].id      
   112 			var found = false ;
   112       var found = false ;
   113 			for (var i = 0, ilen = a.length ; i < ilen ; i++) {
   113       for (var i = 0, ilen = a.length ; i < ilen ; i++) {
   114 				var id2 = a[i] ;
   114         var id2 = a[i] ;
   115 				
   115         
   116 				if (mod[id] < mod[id2]) {
   116         if (mod[id] < mod[id2]) {
   117 					a.splice(i, 0, numberId) ;
   117           a.splice(i, 0, numberId) ;
   118 					found = true ;
   118           found = true ;
   119 					break ;
   119           break ;
   120 				}
   120         }
   121 				
   121         
   122 			}
   122       }
   123 			if (!found)  {
   123       if (!found)  {
   124 				a.push(numberId) ;
   124         a.push(numberId) ;
   125 			}
   125       }
   126 		}
   126     }
   127 		
   127     
   128 		this.ordered_comment_ids['modif_thread'] = a ; 
   128     this.ordered_comment_ids['modif_thread'] = a ; 
   129 	},
   129   },
   130 
   130 
   131    // Finds recursively the last modification date of a thread.
   131    // Finds recursively the last modification date of a thread.
   132   _latest_mod : function(comment) {
   132   _latest_mod : function(comment) {
   133     var latest_mod = comment.modified;
   133     var latest_mod = comment.modified;
   134     for (var i=0; i<comment.replies.length; i++) {
   134     for (var i=0; i<comment.replies.length; i++) {
   138         latest_mod = reply_mod;
   138         latest_mod = reply_mod;
   139     }
   139     }
   140     return latest_mod;
   140     return latest_mod;
   141   },
   141   },
   142 
   142 
   143 	// EDIT OR ADD CASE : when just added id is max and so both (comments and replies) initial id asc order remains
   143   // EDIT OR ADD CASE : when just added id is max and so both (comments and replies) initial id asc order remains
   144 	_upd : function(arr, dic, c) {
   144   _upd : function(arr, dic, c) {
   145 		var found = false ;
   145     var found = false ;
   146 		for (var i = 0, ilen = arr.length ; i < ilen ; i++) {
   146     for (var i = 0, ilen = arr.length ; i < ilen ; i++) {
   147 			if (arr[i].id == c.id) { // edit
   147       if (arr[i].id == c.id) { // edit
   148 				arr.splice(i, 1, c) ;
   148         arr.splice(i, 1, c) ;
   149 				found = true ;
   149         found = true ;
   150 				break ;
   150         break ;
   151 			}
   151       }
   152 		}
   152     }
   153 		
   153     
   154 		if (!found) { // add
   154     if (!found) { // add
   155 			arr.push(c) ;
   155       arr.push(c) ;
   156 		}
   156     }
   157 		
   157     
   158 		dic[c.id] = c ;
   158     dic[c.id] = c ;
   159 	},
   159   },
   160 
   160 
   161 	// EDIT OR ADD CASE : when just added id is max and so both (comments and replies) initial id asc order respected
   161   // EDIT OR ADD CASE : when just added id is max and so both (comments and replies) initial id asc order respected
   162 	upd : function(comment) {
   162   upd : function(comment) {
   163 		var arr = (comment.reply_to_id == null) ? this.allComments : this.allCommentsByDbId[comment.reply_to_id].replies ; 
   163     var arr = (comment.reply_to_id == null) ? this.allComments : this.allCommentsByDbId[comment.reply_to_id].replies ; 
   164 		this._upd(arr, this.allCommentsByDbId, comment) ;
   164     this._upd(arr, this.allCommentsByDbId, comment) ;
   165 		
   165     
   166 		var cloneComment = CY.clone(comment) ;
   166     var cloneComment = CY.clone(comment) ;
   167 		
   167     
   168 		arr = (comment.reply_to_id == null) ? this.comments : this.commentsByDbId[comment.reply_to_id].replies ; 
   168     arr = (comment.reply_to_id == null) ? this.comments : this.commentsByDbId[comment.reply_to_id].replies ; 
   169 		this._upd(arr, this.commentsByDbId, cloneComment) ;
   169     this._upd(arr, this.commentsByDbId, cloneComment) ;
   170 		
   170     
   171 		this._reorder() ;		
   171     this._reorder() ;   
   172 		
   172     
   173 	},
   173   },
   174 
   174 
   175 	// initializes this.comments
   175   // initializes this.comments
   176 	// commentId is the result of a computeFilterResults call : no assumption can be made on the order of ids (!)
   176   // commentId is the result of a computeFilterResults call : no assumption can be made on the order of ids (!)
   177 	// so we'll loop through allComments to carry order from allComments to comments
   177   // so we'll loop through allComments to carry order from allComments to comments
   178 	initComments : function(commentIds) {
   178   initComments : function(commentIds) {
   179 	    this.comments = [] ;
   179       this.comments = [] ;
   180 		for (var i = 0, ilen = this.allComments.length ; i < ilen ; i++) {
   180     for (var i = 0, ilen = this.allComments.length ; i < ilen ; i++) {
   181 			
   181       
   182 			var index = CY.Array.indexOf(commentIds, this.allComments[i].id) ;
   182       var index = CY.Array.indexOf(commentIds, this.allComments[i].id) ;
   183 			if (index != -1) {
   183       if (index != -1) {
   184 				
   184         
   185 				var cloneComment = CY.clone(this.allComments[i]) ;
   185         var cloneComment = CY.clone(this.allComments[i]) ;
   186 				
   186         
   187 				this.comments.push(cloneComment) ;
   187         this.comments.push(cloneComment) ;
   188 			}
   188       }
   189 		}
   189     }
   190 	    this._computeCommentsByDbId() ;
   190       this._computeCommentsByDbId() ;
   191 	},
   191   },
   192 
   192 
   193 	_computeCommentsByDbId : function() {
   193   _computeCommentsByDbId : function() {
   194 		this.commentsByDbId = {} ;
   194     this.commentsByDbId = {} ;
   195 	    var flatComments = this.getThreads(this.comments) ;
   195       var flatComments = this.getThreads(this.comments) ;
   196 		for ( var i = 0; i < flatComments.length; i++)
   196     for ( var i = 0; i < flatComments.length; i++)
   197 			this.commentsByDbId[flatComments[i].id] = flatComments[i];
   197       this.commentsByDbId[flatComments[i].id] = flatComments[i];
   198 	},
   198   },
   199 	
   199   
   200 	_computeAllCommentsByDbId : function() {
   200   _computeAllCommentsByDbId : function() {
   201 		this.allCommentsByDbId = {} ;
   201     this.allCommentsByDbId = {} ;
   202 	    var flatComments = this.getThreads(this.allComments) ;
   202       var flatComments = this.getThreads(this.allComments) ;
   203 		for (var i = 0; i < flatComments.length; i++) 
   203     for (var i = 0; i < flatComments.length; i++) 
   204 			this.allCommentsByDbId[flatComments[i].id] = flatComments[i];
   204       this.allCommentsByDbId[flatComments[i].id] = flatComments[i];
   205 	},
   205   },
   206 	
   206   
   207 	// returns threads :
   207   // returns threads :
   208 	// given an array [comment1, comment2, comment3], this function will return [comment1, comment1reply1, comment1reply1reply1, comment1reply1reply2, comment2, comment3, comment3reply1]
   208   // given an array [comment1, comment2, comment3], this function will return [comment1, comment1reply1, comment1reply1reply1, comment1reply1reply2, comment2, comment3, comment3reply1]
   209 	//note : will return top parents ordered the way comments are
   209   //note : will return top parents ordered the way comments are
   210 	getThreads : function(comments) {
   210   getThreads : function(comments) {
   211 		var ret = [] ;
   211     var ret = [] ;
   212 
   212 
   213 		for (var i = 0 ; i < comments.length ; i++) {
   213     for (var i = 0 ; i < comments.length ; i++) {
   214 			ret.push(comments[i]) ;
   214       ret.push(comments[i]) ;
   215 			if (comments[i].replies.length > 0)
   215       if (comments[i].replies.length > 0)
   216 				ret = ret.concat(this.getThreads(comments[i].replies)) ;
   216         ret = ret.concat(this.getThreads(comments[i].replies)) ;
   217 		}
   217     }
   218 		return ret ;
   218     return ret ;
   219 	},
   219   },
   220 	_getPath : function(dic, comment) {
   220   _getPath : function(dic, comment) {
   221 		var ret = [comment] ;
   221     var ret = [comment] ;
   222 		
   222     
   223 		var c = comment ;
   223     var c = comment ;
   224 		while (c.reply_to_id != null) {
   224     while (c.reply_to_id != null) {
   225 			c = dic[c.reply_to_id] ;
   225       c = dic[c.reply_to_id] ;
   226 			ret.push(c) ;
   226       ret.push(c) ;
   227 		}
   227     }
   228 			
   228       
   229 		return ret ;
   229     return ret ;
   230 	},
   230   },
   231 	// returns comments as array : [comment, ..., comment's top parent]
   231   // returns comments as array : [comment, ..., comment's top parent]
   232 	getPath : function(comment) {
   232   getPath : function(comment) {
   233 		return this._getPath(this.commentsByDbId, comment) ;
   233     return this._getPath(this.commentsByDbId, comment) ;
   234 	},
   234   },
   235 	// getCommentFromIComment ...
   235   // getCommentFromIComment ...
   236 	getComment : function(dbId) {
   236   getComment : function(dbId) {
   237 		return this.commentsByDbId[dbId] ;
   237     return this.commentsByDbId[dbId] ;
   238 	},	
   238   },  
   239 	
   239   
   240 	getCommentByIdKey : function(id_key) {
   240   getCommentByIdKey : function(id_key) {
   241 		for (var id in this.commentsByDbId) {
   241     for (var id in this.commentsByDbId) {
   242 			var comment = this.commentsByDbId[id] ;
   242       var comment = this.commentsByDbId[id] ;
   243 			if (comment.id_key == id_key) { 
   243       if (comment.id_key == id_key) { 
   244 				return comment ;
   244         return comment ;
   245 			}
   245       }
   246 		}
   246     }
   247 		return null ;
   247     return null ;
   248 	},	
   248   },  
   249 	
   249   
   250 	isChild : function(commentDbId, parentDbId) {
   250   isChild : function(commentDbId, parentDbId) {
   251 		var comment = this.commentsByDbId[commentDbId] ;
   251     var comment = this.commentsByDbId[commentDbId] ;
   252 		
   252     
   253 		var isChild = (commentDbId == parentDbId) ;
   253     var isChild = (commentDbId == parentDbId) ;
   254 		
   254     
   255 		while ((!isChild) && (comment.reply_to_id != null)) {
   255     while ((!isChild) && (comment.reply_to_id != null)) {
   256 			comment = this.commentsByDbId[comment.reply_to_id] ;
   256       comment = this.commentsByDbId[comment.reply_to_id] ;
   257 			isChild = (comment.id == parentDbId) ; ;
   257       isChild = (comment.id == parentDbId) ; ;
   258 		}
   258     }
   259 		return isChild ;
   259     return isChild ;
   260 	},	
   260   },  
   261 	
   261   
   262 	initToReadOnly : function(commentDbId, parentDbId) {
   262   initToReadOnly : function(commentDbId, parentDbId) {
   263 		for (var i = 0, ilen = this.allComments.length ; i < ilen ; i++) {
   263     for (var i = 0, ilen = this.allComments.length ; i < ilen ; i++) {
   264 			var comment = this.allComments[i] ;
   264       var comment = this.allComments[i] ;
   265 			for (var prop in comment) {
   265       for (var prop in comment) {
   266 				if (0 == prop.indexOf("can_") && typeof comment[prop] === 'boolean')
   266         if (0 == prop.indexOf("can_") && typeof comment[prop] === 'boolean')
   267 					comment[prop] = false ;
   267           comment[prop] = false ;
   268 			}
   268       }
   269 		}
   269     }
   270 	},	
   270   },  
   271 	
   271   
   272 //////////////////////////////
   272 //////////////////////////////
   273 //	BROWSING FUNCTIONS
   273 //  BROWSING FUNCTIONS
   274 //////////////////////////////
   274 //////////////////////////////
   275 
   275 
   276 	browsingIndex : function(dbId) {
   276   browsingIndex : function(dbId) {
   277 		var indx = {} ;
   277     var indx = {} ;
   278 		for (var order in this.ordered_comment_ids) {
   278     for (var order in this.ordered_comment_ids) {
   279 			var inFilter =  CY.Array.filter(this.ordered_comment_ids[order], function(id) {return (id in this.commentsByDbId);}, this) ;
   279       var inFilter =  CY.Array.filter(this.ordered_comment_ids[order], function(id) {return (id in this.commentsByDbId);}, this) ;
   280 			indx[order] = CY.Array.indexOf(inFilter, dbId ) ;
   280       indx[order] = CY.Array.indexOf(inFilter, dbId ) ;
   281 		}
   281     }
   282 		//indx['total'] = this.ordered_comment_ids['scope'].length
   282     //indx['total'] = this.ordered_comment_ids['scope'].length
   283 		return indx ;
   283     return indx ;
   284 	},
   284   },
   285 	
   285   
   286 	browse : function(order, whereto, dbId) {
   286   browse : function(order, whereto, dbId) {
   287 		//var arr = this.ordered_comment_ids[gConf['defaultBrowsingOrder']] ;
   287     //var arr = this.ordered_comment_ids[gConf['defaultBrowsingOrder']] ;
   288 //		CY.log(order) ;
   288 //    CY.log(order) ;
   289 		var arr = this.ordered_comment_ids[order] ;
   289     var arr = this.ordered_comment_ids[order] ;
   290 		if (arr.length > 0) {
   290     if (arr.length > 0) {
   291 		
   291     
   292 			var starti = -1 ; 
   292       var starti = -1 ; 
   293 			if ((whereto == 'prev') || (whereto == 'next')) {
   293       if ((whereto == 'prev') || (whereto == 'next')) {
   294 				
   294         
   295 				for (var i = 0 ; i < arr.length ; i++) {
   295         for (var i = 0 ; i < arr.length ; i++) {
   296 					var id = arr[i] ;
   296           var id = arr[i] ;
   297 					if (id == dbId) {
   297           if (id == dbId) {
   298 						starti = (whereto == 'prev') ? i - 1 : i + 1 ;
   298             starti = (whereto == 'prev') ? i - 1 : i + 1 ;
   299 						starti = (arr.length + starti) % arr.length ; // to guaranty a positive value 
   299             starti = (arr.length + starti) % arr.length ; // to guaranty a positive value 
   300 						break ;
   300             break ;
   301 					}
   301           }
   302 				}
   302         }
   303 				if (starti == -1) {
   303         if (starti == -1) {
   304 					CY.error("internal error in db browse (was called with a dbId that isn't among the filtered ones)") ;
   304           CY.error("internal error in db browse (was called with a dbId that isn't among the filtered ones)") ;
   305 					return null;
   305           return null;
   306 				}
   306         }
   307 			}
   307       }
   308 			if (whereto == 'last') {
   308       if (whereto == 'last') {
   309 				starti = arr.length - 1 ;
   309         starti = arr.length - 1 ;
   310 			}
   310       }
   311 			if (whereto == 'first') {
   311       if (whereto == 'first') {
   312 				starti = 0 ;
   312         starti = 0 ;
   313 			}
   313       }
   314 	
   314   
   315 			for (var i = starti, j = 0 ; (i >= 0) && (i < arr.length) ; j++ ) {
   315       for (var i = starti, j = 0 ; (i >= 0) && (i < arr.length) ; j++ ) {
   316 				var id = arr[i] ;
   316         var id = arr[i] ;
   317 				if (id in this.commentsByDbId) // checking id is among the filtered ones
   317         if (id in this.commentsByDbId) // checking id is among the filtered ones
   318 					return this.commentsByDbId[id] ;
   318           return this.commentsByDbId[id] ;
   319 				if ((whereto == 'prev') || (whereto == 'last')) 
   319         if ((whereto == 'prev') || (whereto == 'last')) 
   320 					i = i - 1 ;
   320           i = i - 1 ;
   321 				else  
   321         else  
   322 					i = i + 1 ;
   322           i = i + 1 ;
   323 				i = (arr.length + i) % arr.length ; // to guaranty a positive value
   323         i = (arr.length + i) % arr.length ; // to guaranty a positive value
   324 				if (j > arr.length)// to prevent an infinite loop
   324         if (j > arr.length)// to prevent an infinite loop
   325 					break ;
   325           break ;
   326 			}
   326       }
   327 			
   327       
   328 			CY.error("internal error in db browse (could not find any filtered comment)") ;
   328       CY.error("internal error in db browse (could not find any filtered comment)") ;
   329 		}
   329     }
   330 		return null;
   330     return null;
   331 	},
   331   },
   332 	
   332   
   333 //////////////////////////////
   333 //////////////////////////////
   334 //	FILTER FUNCTIONS
   334 //  FILTER FUNCTIONS
   335 //////////////////////////////
   335 //////////////////////////////
   336 	
   336   
   337 	//returns the list of commentIds satisfying the filter
   337   //returns the list of commentIds satisfying the filter
   338 	computeFilterResults : function(filterGETValues) {
   338   computeFilterResults : function(filterGETValues) {
   339 	    var filterData = {} ;
   339       var filterData = {} ;
   340 	    if (filterGETValues) {
   340       if (filterGETValues) {
   341 			for (key in filterGETValues) {
   341       for (key in filterGETValues) {
   342 				if (key.indexOf('filter_') == 0) 
   342         if (key.indexOf('filter_') == 0) 
   343 					filterData[key.substr('filter_'.length)] = filterGETValues[key];
   343           filterData[key.substr('filter_'.length)] = filterGETValues[key];
   344 			}
   344       }
   345 	    }
   345       }
   346 	    else {
   346       else {
   347 			if (gLayout.isInFrame()) 
   347       if (gLayout.isInFrame()) 
   348 				filterData = parent.f_getFrameFilterData() ;
   348         filterData = parent.f_getFrameFilterData() ;
   349 	    }
   349       }
   350 
   350 
   351 		var cWithNameIds = [] ;
   351     var cWithNameIds = [] ;
   352 		var rWithNameIds = [] ;
   352     var rWithNameIds = [] ;
   353 		var filterName = "" ;
   353     var filterName = "" ;
   354 		if ('name' in filterData)
   354     if ('name' in filterData)
   355 			filterName = filterData['name'] ;
   355       filterName = filterData['name'] ;
   356 		this.filterByName(filterName, cWithNameIds, rWithNameIds) ;
   356     this.filterByName(filterName, cWithNameIds, rWithNameIds) ;
   357 		
   357     
   358 		var cAfterDateIds = [] ;
   358     var cAfterDateIds = [] ;
   359 		var rAfterDateIds = [] ;
   359     var rAfterDateIds = [] ;
   360 		var filterDate = "" ;
   360     var filterDate = "" ;
   361 		if ('date' in filterData)
   361     if ('date' in filterData)
   362 			filterDate = filterData['date'] ;
   362       filterDate = filterData['date'] ;
   363 		this.filterByDate(filterDate, cAfterDateIds, rAfterDateIds) ;
   363     this.filterByDate(filterDate, cAfterDateIds, rAfterDateIds) ;
   364 
   364 
   365 		var cWithTextIds = [] ;
   365     var cWithTextIds = [] ;
   366 		var rWithTextIds = [] ;
   366     var rWithTextIds = [] ;
   367 		var filterText = "" ;
   367     var filterText = "" ;
   368 		if ('text' in filterData)
   368     if ('text' in filterData)
   369 			filterText = filterData['text'] ;
   369       filterText = filterData['text'] ;
   370 		this.filterByText(filterText, cWithTextIds, rWithTextIds) ;
   370     this.filterByText(filterText, cWithTextIds, rWithTextIds) ;
   371 		
   371     
   372 		var cWithTagIds = [] ;
   372     var cWithTagIds = [] ;
   373 		var rWithTagIds = [] ;
   373     var rWithTagIds = [] ;
   374 		var filterTag = "" ;
   374     var filterTag = "" ;
   375 		if ('tag' in filterData)
   375     if ('tag' in filterData)
   376 			filterTag = filterData['tag'] ;
   376       filterTag = filterData['tag'] ;
   377 		this.filterByTag(filterTag, cWithTagIds, rWithTagIds) ;
   377     this.filterByTag(filterTag, cWithTagIds, rWithTagIds) ;
   378 		
   378     
   379 		var cWithStateIds = [] ;
   379     var cWithStateIds = [] ;
   380 		var rWithStateIds = [] ;
   380     var rWithStateIds = [] ;
   381 		var filterState = "" ;
   381     var filterState = "" ;
   382 		if ('state' in filterData)
   382     if ('state' in filterData)
   383 			filterState = filterData['state'] ;
   383       filterState = filterData['state'] ;
   384 		this.filterByState(filterState, cWithStateIds, rWithStateIds) ;
   384     this.filterByState(filterState, cWithStateIds, rWithStateIds) ;
   385 		
   385     
   386 		
   386     
   387 		var commentIds = [] ;
   387     var commentIds = [] ;
   388 		var replyIds = [] ;
   388     var replyIds = [] ;
   389 		// find intersections
   389     // find intersections
   390 		for (var i = 0, ilen = cWithNameIds.length ; i < ilen ; i++) {
   390     for (var i = 0, ilen = cWithNameIds.length ; i < ilen ; i++) {
   391 			var id = cWithNameIds[i] ;
   391       var id = cWithNameIds[i] ;
   392 			if ((CY.Array.indexOf(cAfterDateIds, id) != -1) && (CY.Array.indexOf(cWithTextIds,id) != -1) && (CY.Array.indexOf(cWithTagIds,id) != -1) && (CY.Array.indexOf(cWithStateIds,id) != -1)) {
   392       if ((CY.Array.indexOf(cAfterDateIds, id) != -1) && (CY.Array.indexOf(cWithTextIds,id) != -1) && (CY.Array.indexOf(cWithTagIds,id) != -1) && (CY.Array.indexOf(cWithStateIds,id) != -1)) {
   393 				commentIds.push(id) ; 
   393         commentIds.push(id) ; 
   394 			}
   394       }
   395 		}
   395     }
   396 		
   396     
   397 		for (var i = 0, ilen = rWithNameIds.length ; i < ilen ; i++) {
   397     for (var i = 0, ilen = rWithNameIds.length ; i < ilen ; i++) {
   398 			var id = rWithNameIds[i] ;
   398       var id = rWithNameIds[i] ;
   399 			if ((CY.Array.indexOf(rAfterDateIds,id) != -1) && (CY.Array.indexOf(rWithTextIds,id) != -1) && (CY.Array.indexOf(rWithTagIds,id) != -1) && (CY.Array.indexOf(rWithStateIds,id) != -1)) {
   399       if ((CY.Array.indexOf(rAfterDateIds,id) != -1) && (CY.Array.indexOf(rWithTextIds,id) != -1) && (CY.Array.indexOf(rWithTagIds,id) != -1) && (CY.Array.indexOf(rWithStateIds,id) != -1)) {
   400 				replyIds.push(id) ; 
   400         replyIds.push(id) ; 
   401 			}
   401       }
   402 		}
   402     }
   403 		
   403     
   404 		var nbReplies = replyIds.length, nbComments = commentIds.length ;
   404     var nbReplies = replyIds.length, nbComments = commentIds.length ;
   405 		var nbDiscussions = nbComments ;
   405     var nbDiscussions = nbComments ;
   406 		
   406     
   407 		// look for comments to add because a reply satisfies the filter
   407     // look for comments to add because a reply satisfies the filter
   408 //		CY.log('replyIds:') ;
   408 //    CY.log('replyIds:') ;
   409 //		CY.log(replyIds) ;
   409 //    CY.log(replyIds) ;
   410 //		CY.log('this.allCommentsByDbId :');CY.A
   410 //    CY.log('this.allCommentsByDbId :');CY.A
   411 //		CY.log(this.allCommentsByDbId);
   411 //    CY.log(this.allCommentsByDbId);
   412 		for (var i = 0, ilen = replyIds.length ; i < ilen ; i++) {
   412     for (var i = 0, ilen = replyIds.length ; i < ilen ; i++) {
   413 			var id = replyIds[i] ;
   413       var id = replyIds[i] ;
   414 			var reply = this.allCommentsByDbId[id] ;
   414       var reply = this.allCommentsByDbId[id] ;
   415 			var parents = this._getPath(this.allCommentsByDbId, reply) ;
   415       var parents = this._getPath(this.allCommentsByDbId, reply) ;
   416 			var topComment = parents[parents.length - 1] ;
   416       var topComment = parents[parents.length - 1] ;
   417 			var id = topComment.id ;
   417       var id = topComment.id ;
   418 			if (CY.Array.indexOf(commentIds,id) == -1) {
   418       if (CY.Array.indexOf(commentIds,id) == -1) {
   419 				commentIds.push(id) ;
   419         commentIds.push(id) ;
   420 				nbDiscussions++ ;
   420         nbDiscussions++ ;
   421 			}
   421       }
   422 		}
   422     }
   423 		
   423     
   424 		return {'commentIds': commentIds,'nbDiscussions':nbDiscussions, 'nbComments':nbComments, 'nbReplies':nbReplies} ;
   424     return {'commentIds': commentIds,'nbDiscussions':nbDiscussions, 'nbComments':nbComments, 'nbReplies':nbReplies} ;
   425 	},
   425   },
   426 
   426 
   427 	filterByText : function(text, cWithTextIds, rWithTextIds) {
   427   filterByText : function(text, cWithTextIds, rWithTextIds) {
   428 		var re = new RegExp(text, "gi");
   428     var re = new RegExp(text, "gi");
   429 		for (var id in this.allCommentsByDbId) {
   429     for (var id in this.allCommentsByDbId) {
   430 			var comment = this.allCommentsByDbId[id] ;
   430       var comment = this.allCommentsByDbId[id] ;
   431 			if (text == "" || re.exec(comment.title) != null || re.exec(comment.content) != null) { // search only in the comment (not the comment scope) for now
   431       if (text == "" || re.exec(comment.title) != null || re.exec(comment.content) != null) { // search only in the comment (not the comment scope) for now
   432 				if (comment.reply_to_id == null) 
   432         if (comment.reply_to_id == null) 
   433 					cWithTextIds.push(comment.id);
   433           cWithTextIds.push(comment.id);
   434 				else 
   434         else 
   435 					rWithTextIds.push(comment.id) ;
   435           rWithTextIds.push(comment.id) ;
   436 			}
   436       }
   437 		}
   437     }
   438 	},
   438   },
   439 
   439 
   440 	filterByName : function(name, cWithNameIds, rWithNameIds) {
   440   filterByName : function(name, cWithNameIds, rWithNameIds) {
   441 		for (var id in this.allCommentsByDbId) {
   441     for (var id in this.allCommentsByDbId) {
   442 			var comment = this.allCommentsByDbId[id] ;
   442       var comment = this.allCommentsByDbId[id] ;
   443 			if (name == "" || comment.name == name) { // sensitive exact match for now
   443       if (name == "" || comment.name == name) { // sensitive exact match for now
   444 				if (comment.reply_to_id == null) 
   444         if (comment.reply_to_id == null) 
   445 					cWithNameIds.push(comment.id);
   445           cWithNameIds.push(comment.id);
   446 				else 
   446         else 
   447 					rWithNameIds.push(comment.id) ;
   447           rWithNameIds.push(comment.id) ;
   448 			}
   448       }
   449 		}
   449     }
   450 	},
   450   },
   451 
   451 
   452 	// warning : tags are case sensitive
   452   // warning : tags are case sensitive
   453 	filterByTag : function(tag, cWithTagIds, rWithTagIds) {
   453   filterByTag : function(tag, cWithTagIds, rWithTagIds) {
   454 		// cf ", ".join... in client.py	
   454     // cf ", ".join... in client.py 
   455 		var re0 = new RegExp("^" + tag + "$", "g"); 
   455     var re0 = new RegExp("^" + tag + "$", "g"); 
   456 		var re1 = new RegExp("^" + tag + ", ", "g");
   456     var re1 = new RegExp("^" + tag + ", ", "g");
   457 		var re2 = new RegExp(", " + tag + ", ", "g"); 
   457     var re2 = new RegExp(", " + tag + ", ", "g"); 
   458 		var re3 = new RegExp(", " + tag + "$", "g"); 
   458     var re3 = new RegExp(", " + tag + "$", "g"); 
   459 		for (var id in this.allCommentsByDbId) {
   459     for (var id in this.allCommentsByDbId) {
   460 			var comment = this.allCommentsByDbId[id] ;
   460       var comment = this.allCommentsByDbId[id] ;
   461 			if (tag == "" || re0.exec(comment.tags) || re1.exec(comment.tags) != null || re2.exec(comment.tags) != null || re3.exec(comment.tags) != null) { // search only in the comment (not the comment scope) for now
   461       if (tag == "" || re0.exec(comment.tags) || re1.exec(comment.tags) != null || re2.exec(comment.tags) != null || re3.exec(comment.tags) != null) { // search only in the comment (not the comment scope) for now
   462 				if (comment.reply_to_id == null) 
   462         if (comment.reply_to_id == null) 
   463 					cWithTagIds.push(comment.id);
   463           cWithTagIds.push(comment.id);
   464 				else 
   464         else 
   465 					rWithTagIds.push(comment.id) ;
   465           rWithTagIds.push(comment.id) ;
   466 			}
   466       }
   467 		}
   467     }
   468 	},
   468   },
   469 
   469 
   470 	filterByState : function(state, cWithStateIds, rWithStateIds) {
   470   filterByState : function(state, cWithStateIds, rWithStateIds) {
   471 		for (var id in this.allCommentsByDbId) {
   471     for (var id in this.allCommentsByDbId) {
   472 			var comment = this.allCommentsByDbId[id] ;
   472       var comment = this.allCommentsByDbId[id] ;
   473 			if (state == "" || comment.state == state) { 
   473       if (state == "" || comment.state == state) { 
   474 				if (comment.reply_to_id == null) 
   474         if (comment.reply_to_id == null) 
   475 					cWithStateIds.push(comment.id);
   475           cWithStateIds.push(comment.id);
   476 				else 
   476         else 
   477 					rWithStateIds.push(comment.id) ;
   477           rWithStateIds.push(comment.id) ;
   478 			}
   478       }
   479 		}
   479     }
   480 	},
   480   },
   481 
   481 
   482 	filterByDate : function(date_str, cAfterDateIds, rAfterDateIds) {
   482   filterByDate : function(date_str, cAfterDateIds, rAfterDateIds) {
   483 		var date = (date_str == "") ? 0 : parseInt(date_str) ;
   483     var date = (date_str == "") ? 0 : parseInt(date_str) ;
   484 		for (var id in this.allCommentsByDbId) {
   484     for (var id in this.allCommentsByDbId) {
   485 			var comment = this.allCommentsByDbId[id] ;
   485       var comment = this.allCommentsByDbId[id] ;
   486 			if (comment.modified > date) { 
   486       if (comment.modified > date) { 
   487 				if (comment.reply_to_id == null) 
   487         if (comment.reply_to_id == null) 
   488 					cAfterDateIds.push(comment.id); 
   488           cAfterDateIds.push(comment.id); 
   489 				else 
   489         else 
   490 					rAfterDateIds.push(comment.id) ;
   490           rAfterDateIds.push(comment.id) ;
   491 			}
   491       }
   492 		}
   492     }
   493 	},
   493   },
   494 //	filterByDate : function(date_str, cAfterDateIds, rAfterDateIds) {
   494 //  filterByDate : function(date_str, cAfterDateIds, rAfterDateIds) {
   495 //		var date = (date_str == "") ? "" : Date.parseDate(date_str, sv_client_date_fmt).getTime() ;
   495 //    var date = (date_str == "") ? "" : Date.parseDate(date_str, sv_client_date_fmt).getTime() ;
   496 //		for (var id in this.allCommentsByDbId) {
   496 //    for (var id in this.allCommentsByDbId) {
   497 //			var comment = this.allCommentsByDbId[id] ;
   497 //      var comment = this.allCommentsByDbId[id] ;
   498 //			// TODO : created should be the date not a string !!
   498 //      // TODO : created should be the date not a string !!
   499 //			var create_date = (date_str == "") ? "" : Date.parseDate(comment.created_str, sv_client_date_fmt).getTime() ;
   499 //      var create_date = (date_str == "") ? "" : Date.parseDate(comment.created_str, sv_client_date_fmt).getTime() ;
   500 //			if (date_str == "" || create_date > date) { 
   500 //      if (date_str == "" || create_date > date) { 
   501 //				if (comment.reply_to_id == null) 
   501 //        if (comment.reply_to_id == null) 
   502 //					cAfterDateIds.push(comment.id); 
   502 //          cAfterDateIds.push(comment.id); 
   503 //				else 
   503 //        else 
   504 //					rAfterDateIds.push(comment.id) ;
   504 //          rAfterDateIds.push(comment.id) ;
   505 //			}
   505 //      }
   506 //		}
   506 //    }
   507 //	},
   507 //  },
   508 	
   508   
   509 //////////////////////////////
   509 //////////////////////////////
   510 //	COUNT FUNCTIONS
   510 //  COUNT FUNCTIONS
   511 //////////////////////////////
   511 //////////////////////////////
   512 	
   512   
   513 	getCommentsAndRepliesCounts : function(all) {
   513   getCommentsAndRepliesCounts : function(all) {
   514 		var cCount = 0 ;
   514     var cCount = 0 ;
   515 		var rCount = 0 ;
   515     var rCount = 0 ;
   516 		var arr = (all) ? this.allComments:this.comments;
   516     var arr = (all) ? this.allComments:this.comments;
   517 	    var flatComments = this.getThreads(arr) ;
   517       var flatComments = this.getThreads(arr) ;
   518 		for ( var i = 0; i < flatComments.length; i++) {
   518     for ( var i = 0; i < flatComments.length; i++) {
   519 			if (flatComments[i].reply_to_id == null)
   519       if (flatComments[i].reply_to_id == null)
   520 				cCount++ ;
   520         cCount++ ;
   521 			else 
   521       else 
   522 				rCount++ ;
   522         rCount++ ;
   523 		}
   523     }
   524 		return [cCount, rCount] ;
   524     return [cCount, rCount] ;
   525 	},
   525   },
   526 
   526 
   527 	// counts both comments and comments 
   527   // counts both comments and comments 
   528 	getCommentsNb : function(all) {
   528   getCommentsNb : function(all) {
   529 		var arr = (all) ? this.allComments:this.comments;
   529     var arr = (all) ? this.allComments:this.comments;
   530 	    return this.getThreads(arr).length ;
   530       return this.getThreads(arr).length ;
   531 	},
   531   },
   532 	getFilteredCommentIdsAsString : function() {
   532   getFilteredCommentIdsAsString : function() {
   533 		var ret = "" ;
   533     var ret = "" ;
   534 		for (var id in this.commentsByDbId) 
   534     for (var id in this.commentsByDbId) 
   535 			ret = ret + id + "," ;
   535       ret = ret + id + "," ;
   536 		return ret ;
   536     return ret ;
   537 	}
   537   }
   538 }
   538 }
   539 
   539 
   540 
   540