src/cm/media/js/client/c_sync.js
changeset 0 40c8f766c9b8
child 12 f69ff46d3240
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/cm/media/js/client/c_sync.js	Mon Nov 23 15:14:29 2009 +0100
@@ -0,0 +1,482 @@
+gShowingAllComments = false ;
+// YUI : queue, overlay
+Sync = function() {
+	// this queue handles both animations and io requests
+	this._q = null ;
+	
+	this._iPreventClick = false ; // oh really ?
+}
+
+Sync.prototype = {
+	init : function (iComment) {
+	this._q = new CY.AsyncQueue() ;
+// pr2 this._q = new CY.Queue() ;
+	},
+	
+	setPreventClickOn : function () {
+		CY.log("setPreventClickOn !") ;
+		if (gLayout.isInFrame())
+			parent.f_interfaceFreeze()		
+		this._iPreventClick = true ;
+	},
+
+	setPreventClickOff : function () {
+		CY.log("setPreventClickOff !") ;
+		if (gLayout.isInFrame())
+			parent.f_interfaceUnfreeze()		
+		this._iPreventClick = false ;
+	},
+
+	removeCommentRet : function(args) {
+		var successfull = args['successfull'] ;
+		
+		var iComment = (successfull) ? args['failure']['iComment'] : args['success']['iComment'] ;
+		
+		if (successfull) {
+			var filterData = args['returned']['filterData'] ;
+			if (gLayout.isInFrame()) {
+				parent.f_updateFilterData(filterData) ;
+			}
+			
+			var y = gIComments.getTopPosition()[1] ;
+			
+			var comment = gDb.getComment(iComment.commentId) ;
+			this._q.add(
+		            function(){
+		            	
+		    	    	unpaintCommentScope(comment) ;
+		    	    	gIComments.close(comment.id) ;
+		    	    	gIComments.remove(comment.id) ;
+		    	    	if (comment.reply_to_id != null)
+		    	    		gIComments.refresh(comment.reply_to_id) ;
+		    	    	
+		    	    	gDb.del(comment) ;
+		    	    	
+		    	    	if (gLayout.isInFrame()) {
+		    		    	if (gDb.comments.length == 0 && gDb.allComments.length != 0) {
+		    		    		parent.f_enqueueMsg(gettext("no filtered comments left")) ;
+		    					parent.resetFilter() ;  
+		    		    	}
+		    		    	else {
+		    					// just counting here ...
+		    					var filterRes = gDb.computeFilterResults() ;
+		    					updateFilterResultsCount(filterRes['nbDiscussions'], filterRes['nbComments'], filterRes['nbReplies']) ;
+		    		    	}
+		    	    	}
+		            }
+			);
+			
+			this._animateTo(y) ;		
+		}
+		this._q.add({fn:CY.bind(this.setPreventClickOff, this)}) ;
+		this.resume() ;
+	},
+	
+	moderateCommentRet : function(args) {
+		var successfull = args['successfull'] ;
+
+		var iComment = (successfull) ? args['failure']['iComment'] : args['success']['iComment'] ;
+
+		if (successfull) {
+			var ret = args['returned'] ;
+			var comment = ret['comment'] ;
+
+			gDb.upd(comment) ;
+			
+			var shouldReset = gLayout.isInFrame() && !parent.f_isFrameFilterFieldsInit() ;
+			if (shouldReset){
+				parent.resetFilter() ;
+				this._showSingleComment(comment) ;
+			}
+			else 
+				iComment.changeModeration(comment) ;
+		}
+
+		this._q.add({fn:CY.bind(this.setPreventClickOff, this)}) ;
+		this.resume() ;
+	},
+	
+	saveCommentRet : function(args) {
+		var successfull = args['successfull'] ;
+		if (successfull) {
+			var formId = args['success']['formId'] ;
+			var ret = args['returned'] ;
+		
+			removeFormErrMsg(formId) ;
+		
+			if ('errors' in ret) { // validation error
+				var errors = ret['errors'] ;
+				for (var eltName in errors) {
+					addFormErrMsg(formId, eltName, errors[eltName]) ;
+				}
+				this._animateToTop() ;
+			}
+			else {
+				var isReply = function() {return (gNewReply != null) && (formId == gNewReply['ids']['formId']) ;} ;
+				var isNewComment = function() {return (gICommentForm != null) && (formId == gICommentForm['formId']) ;} ;
+				var isEdit = function() {return (gEdit != null) && (formId == gEdit['ids']['formId']) ;} ;
+				
+				// doing this here for the a priori moderation case
+				if (isNewComment())
+					this.hideICommentForm(cleanICommentForm()) ;
+				else if (isEdit())
+					this._hideEditForm() ;
+				else if (isReply())
+					this._hideNewReplyForm() ;
+				
+				if ("comment" in ret) { // won't be when add with a priori moderation
+					var comment = ret['comment'] ;
+	
+					gDb.upd(comment) ;
+	
+					var shouldReset = gLayout.isInFrame() && !parent.f_isFrameFilterFieldsInit() ;
+					if (shouldReset)
+						parent.resetFilter() ;
+					else { // ASSUMING filter is in init state ! (because when not // TODO $$$$$$$$$$$ this isn't true anymore .... when passing filter arguments in url !!
+							// in frame for now data can't be filtered)
+						if (comment.reply_to_id == null) { // not a reply
+							unpaintCommentScope(comment) ; // for the edit case
+							paintCommentScope(comment) ;
+						}
+					}
+	
+					// UPDATE FILTER DATA // TODO move ????
+					var filterData = ret['filterData'] ;
+					if (gLayout.isInFrame()) {
+						parent.f_updateFilterData(filterData) ;
+						updateResetFilterResultsCount() ;				
+					}
+
+					if (isReply()) { // add reply case
+						if (!shouldReset) {
+							this._insertReply(comment) ;
+						}
+					}
+					else { // edit (reply or comment) or add (comment) case
+				    	this._showSingleComment(comment) ;
+					}
+				}
+				else 
+					this._animateToTop() ;
+			}
+
+		}
+		else { // TODO ? ALL ret-FUNCTIONS ?
+			this._q.add({id:"expl", fn:function () {CY.log('in example .........') ;}}) ;
+			this._q.promote("expl") ;
+		}
+
+		this._q.add({fn:CY.bind(this.setPreventClickOff, this)}) ;
+		this.resume() ;
+	},
+	
+	example : function () {
+		CY.log('in example .........') ;
+	},
+
+	moderateComment	: function(iComment, state) {
+		var comment = gDb.getComment(iComment['commentId']) ;
+        this._q.add(
+	            {fn:CY.bind(this.setPreventClickOn, this)},
+	            {autoContinue:false, fn:CY.bind(doExchange, null, "editComment", {'comment_key':comment.key, 'state':state}, null, this.moderateCommentRet, this, {'iComment':iComment}, gettext("could not save comment"))}
+	            ).run();
+	},
+	
+	_saveComment : function(serverFun, formId) {
+        this._q.add(
+	            {fn:CY.bind(this.setPreventClickOn, this)},
+	            {autoContinue:false, fn:CY.bind(doExchange, null, serverFun, {}, formId, this.saveCommentRet, this, {'formId':formId}, gettext("could not save comment"))}
+	            ).run();
+	},
+	
+	editComment : function() {
+		this._saveComment("editComment", gEdit['ids']['formId']) ;
+	},
+	
+	saveComment : function(formId) {
+		this._saveComment("addComment", formId) ;
+	},
+	
+	removeComment : function(iComment) {
+		checkForOpenedDialog(iComment, function() {
+			if (gLayout.isInFrame()) {
+				parent.f_yesNoDialog(gettext("Are you sure you want to delete this comment?"), gettext("Warning"), function() { this.animateToTop() ;}, this, null, function() {
+					var comment = gDb.getComment(iComment.commentId) ;
+			        this._q.add(
+				            {fn:CY.bind(this.setPreventClickOn, this)},
+				            {autoContinue:false, fn:CY.bind(doExchange, null, "removeComment", {'comment_key':comment.key}, null, this.removeCommentRet, this, {'iComment':iComment}, gettext("could not remove comment"))}
+				            ).run();
+				}, this, null) ;
+		        
+			}
+//			else {
+//				alert("TODO : can't yet delete comments when not embed in text_view_frame because can't 'dialog' confirmation") ;
+//			}
+		
+		}, this, null) ;
+	},
+	
+	resume : function(commentDbIds, mouseXY) {
+		this._q.run() ;
+	},
+	
+	resetAutoContinue : function(callbackId) {
+		this._q.getCallback(callbackId).autoContinue = true;
+	},
+	
+	hideICommentForm : function(funObj) {
+//		this._q.add({fn:function() {persistICommentFormValues();}}) ;
+		this._q.add({autoContinue:false, fn:CY.bind(gICommentForm['animationHide'].run, gICommentForm['animationHide'])}) ;
+//		this._q.add({fn:function() {cleanICommentForm();}}) ;
+		if (funObj)
+			this._q.add(funObj) ;
+	},
+	
+	/* ANIMATION DRIVEN INTERFACE CHANGES */
+	
+	showCommentForm : function(iComment) {
+		checkForOpenedDialog(null, function() {
+	        this._q.add({fn:CY.bind(this.setPreventClickOn, this)});
+			this._q.add({fn:function() {
+								if (iComment == null) {
+									var selection = getSelectionInfo() ;
+									updateICommentFormSelection(selection) ;
+								}
+								showICommentForm(iComment);
+							}}) ;
+			this._q.add({autoContinue:false, fn:CY.bind(gICommentForm['animationShow'].run, gICommentForm['animationShow'])},
+					{fn:CY.bind(this.setPreventClickOff, this)}
+					).run();
+		}, this, null) ;
+	},
+	
+	showEditForm : function(iComment) {
+		checkForOpenedDialog(null, function() {
+	        this._q.add({fn:CY.bind(this.setPreventClickOn, this)});
+
+	        this._q.add({fn:function() {
+	        				showEditForm(iComment) ;
+	        			}});
+			this._animateToTop() ;
+			
+	        this._q.add({fn:CY.bind(this.setPreventClickOff, this)});
+	        this._q.run() ;
+		}, this, null) ;
+	},
+	
+	showReplyForm : function(iComment) {
+		checkForOpenedDialog(null, function() {
+	        this._q.add({fn:CY.bind(this.setPreventClickOn, this)});
+
+	        this._q.add({fn:function() {
+	        					instanciateNewReplyForm(iComment) ;
+	        					}});
+			this._animateToTop() ;
+			
+	        this._q.add({fn:CY.bind(this.setPreventClickOff, this)});
+	        this._q.run() ;
+		}, this, null) ;
+	},
+	
+	cancelICommentForm : function() {
+        this._q.add({fn:CY.bind(this.setPreventClickOn, this)});
+        
+//		this._q.add({fn:function() {cleanICommentForm();}}) ;
+    	this.hideICommentForm() ;
+    	
+        this._q.add({fn:CY.bind(this.setPreventClickOff, this)});
+        this._q.run() ;
+	},
+	cancelEdit : function() {
+        this._q.add({fn:CY.bind(this.setPreventClickOn, this)});
+        
+    	this._q.add({fn:function() {cancelEditForm();}}) ;
+    	this._animateToTop() ;
+    	
+        this._q.add({fn:CY.bind(this.setPreventClickOff, this)});
+        this._q.run() ;
+	},
+	cancelReply : function() {
+        this._q.add({fn:CY.bind(this.setPreventClickOn, this)});
+        
+    	this._q.add({fn:function() {cancelNewReplyForm();}}) ;
+    	this._animateToTop() ;
+    	
+        this._q.add({fn:CY.bind(this.setPreventClickOff, this)});
+        this._q.run() ;
+	},
+	changeScopeFormClick : function() {
+        this._q.add({fn:CY.bind(this.setPreventClickOn, this)});
+        
+    	this._q.add({fn:function() {changeScopeFormClick();}}) ;
+    	this._animateToTop() ;
+    	
+        this._q.add({fn:CY.bind(this.setPreventClickOff, this)});
+        this._q.run() ;
+	},
+	// this is invoked during queue execution
+	_hideNewReplyForm : function() {
+		this._q.add({fn:function() {
+					cleanNewReplyForm() ; 
+					cancelNewReplyForm() ;}}) ;
+	},
+	// this is invoked during queue execution
+	_hideEditForm : function() {
+		this._q.add({fn:function() {
+					cancelEditForm() ;}}) ;
+	},
+	// this is invoked during queue execution
+	_insertReply : function(comment) {
+		this._q.add({fn:function() {
+					var parentComment = gDb.getComment(comment.reply_to_id) ;
+					var parentThread = gDb.getThreads([parentComment]) ;
+					var previousComment = parentThread[parentThread.length - 2] ; // - 2 because now that comment has been added comment is parentThread[parentThread.length - 1]
+
+					var iComment = gIComments.insertAfter(previousComment, comment) ;
+					// iComment CAN'T BE NULL ! (TODO check that there is a
+					// check server side that parent exists when adding a reply
+					// !)
+					
+					var parentPosition = gIComments.getPosition(comment.reply_to_id) ;
+					iComment.setPosition(parentPosition) ;
+					
+					// check if activation is necessary (will always be ?)
+					var comment_path = gDb.getPath(comment) ;
+					var topComment = comment_path[comment_path.length - 1] ;
+					if (gIComments.isTopActive(topComment.id))
+						iComment.activate() ;
+
+					iComment.show() ;}}) ;
+    	this._animateToTop() ;
+	},
+	_showSingleComment : function(comment) {
+		if (comment != null) {
+			var path = gDb.getPath(comment) ;
+			var topAncestorComment = path[path.length - 1] ;
+			var topY = CY.get(".c-id-"+topAncestorComment.id).getY() ;
+			this._showComments([topAncestorComment.id], topY, false) ;
+			// optim when browsing comments with no reply			
+			if (topAncestorComment.replies.length > 0)
+				this._animateTo(topY) ;
+		}
+	},
+
+	showSingleComment : function(comment) {
+		this._q.add({fn:CY.bind(this.setPreventClickOn, this)}) ;
+		this._showSingleComment(comment) ;
+		this._q.add({fn:CY.bind(this.setPreventClickOff, this)}) ;
+		this._q.run();
+	},
+	
+	browse : function(order, whereto) { 
+		var comment = gIComments.browse(order, whereto) ;
+		if (comment != null) 
+			this.showSingleComment(comment) ;
+	},
+	
+	_showComments : function(commentDbIds, topY, showingAll) {
+		this._q.add(
+			{fn:function() {
+				gShowingAllComments = showingAll ;			
+				gIComments.hide() ; 
+				var cs = CY.Array.map(commentDbIds, function(id) { return gDb.getComment(id) ; }) ;
+				var comments = gDb.getThreads(cs) ;
+				gIComments.fetch(comments) ;
+	
+				if (commentDbIds.length > 0) {
+					if (!showingAll) {
+						gIComments.activate(commentDbIds[0]) ;
+						var scopeStart = CY.get(".c-id-"+commentDbIds[0]) ;
+						if (!scopeStart.inViewportRegion())
+							scopeStart.scrollIntoView(true) ;
+					}
+					else {
+						CY.get('document').set('scrollTop', 0) ; 
+					}
+				}
+				
+				gIComments.setPosition([gConf['iCommentLeftPadding'], topY]) ;
+	
+				gIComments.show() ;
+			}}) ;
+	},
+	
+	_animateTo : function(topY) {
+		this._q.add({fn:function() {
+						gIComments.setAnimationToPositions(topY) ;
+						}},
+					{id:"animationRun", autoContinue:false, fn:CY.bind(gIComments.runAnimations, gIComments)}
+	            ) ;
+	},
+	
+	_animateToTop : function() {
+		var topPos = gIComments.getTopPosition() ;
+		if (topPos != null)
+			this._animateTo(topPos[1]) ;
+	},
+	
+	animateToTop : function() {
+		this._q.add({fn:CY.bind(this.setPreventClickOn, this)}) ;
+		this._animateToTop() ;
+		this._q.add({fn:CY.bind(this.setPreventClickOff, this)}) ;
+		this._q.run();
+	},
+	
+	showAllComments : function() {
+		checkForOpenedDialog(null, function() {
+			gShowingAllComments = true ;
+			var allTopComments = CY.Array.map(gDb.comments, function(c){return c.id;}) ;
+			this.showComments(allTopComments, [0,0], true) ;
+		}, this, null) ;
+	},
+
+	showComments : function(commentDbIds, mouseXY, showingAll) {
+		checkForOpenedDialog(null, function() {
+			this._q.add({fn:CY.bind(this.setPreventClickOn, this)}) ;
+			this._showComments(commentDbIds, mouseXY[1], showingAll) ;
+			this._animateTo(mouseXY[1]) ;
+			this._q.add({fn:CY.bind(this.setPreventClickOff, this)}) ;
+			this._q.run();
+		}, this, null) ;
+	},
+
+	openComment : function(iComment) { 
+		this._q.add({fn:CY.bind(this.setPreventClickOn, this)}) ;
+
+		var y = gIComments.getTopPosition()[1] ;
+		this._q.add({fn:function() {
+			gIComments.open(iComment.commentId) ;
+    		gIComments.refresh(iComment.commentId) ;
+		}}) ;
+		this._animateTo(y) ;
+		
+		this._q.add({fn:CY.bind(this.setPreventClickOff, this)}) ;
+		this._q.run();
+	},
+	
+	closeComment : function(iComment) { 
+		checkForOpenedDialog(iComment, function() {
+			this._q.add({fn:CY.bind(this.setPreventClickOn, this)}) ;
+	
+			var y = gIComments.getTopPosition()[1] ;
+			this._q.add({fn:function() {
+				var comment = gDb.getComment(iComment.commentId) ;
+				gIComments.close(iComment.commentId) ;
+		    	if (comment.reply_to_id != null)
+		    		gIComments.refresh(comment.reply_to_id) ;
+			}}) ;
+			this._animateTo(y) ;
+	
+			this._q.add({fn:CY.bind(this.setPreventClickOff, this)}) ;
+			this._q.run() ;
+		}, this, null) ;
+	},
+	
+	activate : function(iComment) {
+		gIComments.activate(iComment.commentId) ;
+	}
+}
+			
+readyForAction = function () {
+	return !gSync._iPreventClick ;
+};