diff -r 000000000000 -r 40c8f766c9b8 src/cm/media/js/client/c_sync.js --- /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 ; +};