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