src/cm/media/js/client/c_icomment.js
changeset 341 053551f213fb
parent 339 0508284129cf
child 389 eecda8559c1d
equal deleted inserted replaced
340:9e2b9e568e42 341:053551f213fb
     1 // globals used: gConf, gPrefs, gLayout, gSync
     1 // globals used: gConf, gPrefs, gLayout, gSync
     2 
     2 
     3 
     3 
     4 // IComment == IHM comment class 
     4 // IComment == IHM comment class 
     5 IComment = function() {
     5 IComment = function() {
     6 	
     6   
     7 	this.commentId = null ;
     7   this.commentId = null ;
     8 	
     8   
     9 	var iCommentWidth = gLayout.getTopICommentsWidth() ;	
     9   var iCommentWidth = gLayout.getTopICommentsWidth() ;  
    10 	var iCommentLeft = gConf['iCommentLeftPadding'] ;
    10   var iCommentLeft = gConf['iCommentLeftPadding'] ;
    11 	
    11   
    12 	var changeToPending = gettext("change comment state to pending") ;
    12   var changeToPending = gettext("change comment state to pending") ;
    13 	var changeToApprove = gettext("change comment state to approved") ;
    13   var changeToApprove = gettext("change comment state to approved") ;
    14 	var changeToUnapprove= gettext("change comment state to unapproved") ;
    14   var changeToUnapprove= gettext("change comment state to unapproved") ;
    15 	var cancelChange = gettext("cancel changing the state of this comment") ;
    15   var cancelChange = gettext("cancel changing the state of this comment") ;
    16 	var pending = gettext("pending") ;
    16   var pending = gettext("pending") ;
    17 	var approved = gettext("approved") ;
    17   var approved = gettext("approved") ;
    18 	var unapproved = gettext("unapproved") ;
    18   var unapproved = gettext("unapproved") ;
    19 	var cancel = gettext("cancel") ;
    19   var cancel = gettext("cancel") ;
    20 	var showReplies = gettext("show replies") ;
    20   var showReplies = gettext("show replies") ;
    21 	var changeTo= gettext("change to:") ;
    21   var changeTo= gettext("change to:") ;
    22 	var reply = ngettext("reply","replies",1) ; // hack to get django to add 'replies' as the plural in f_text_view_frame !!
    22   var reply = ngettext("reply","replies",1) ; // hack to get django to add 'replies' as the plural in f_text_view_frame !!
    23 	var editComment = gettext("edit comment") ;
    23   var editComment = gettext("edit comment") ;
    24 	var deleteComment = gettext("delete comment") ;
    24   var deleteComment = gettext("delete comment") ;
    25 	var edit = gettext("edit") ;
    25   var edit = gettext("edit") ;
    26 	var del = gettext("delete") ;
    26   var del = gettext("delete") ;
    27 	var close = gettext("close") ;
    27   var close = gettext("close") ;
    28 	var showScope = gettext("show scope") ;
    28   var showScope = gettext("show scope") ;
    29 	var scopeRemoved = gettext("Comment is detached: it was created on a previous version and text it applied to has been modified or removed.") ;
    29   var scopeRemoved = gettext("Comment is detached: it was created on a previous version and text it applied to has been modified or removed.") ;
    30 	
    30   
    31 	// no header, no body yet 
    31   // no header, no body yet 
    32 	this.overlay = new CY.Overlay( {
    32   this.overlay = new CY.Overlay( {
    33 		zIndex :3,
    33     zIndex :3,
    34 		shim :false, /* until we really need it, no shim */
    34     shim :false, /* until we really need it, no shim */
    35 		visible :false,
    35     visible :false,
    36 		width : iCommentWidth,
    36     width : iCommentWidth,
    37 		xy : [ iCommentLeft, 0 ],
    37     xy : [ iCommentLeft, 0 ],
    38 		headerContent :	'<div class="icomment-header">' +
    38     headerContent : '<div class="icomment-header">' +
    39 							'<div class="c-iactions">' +  
    39               '<div class="c-iactions">' +  
    40 								'<a class="c-moderate c-action" title="">'+ "vis" +'</a>' + " " +  
    40                 '<a class="c-moderate c-action" title="">'+ "vis" +'</a>' + " " +  
    41 								'<a class="c-edit c-action" title="'+ editComment +'" alt="' + editComment + '">' + edit + '</a>' + " " +   
    41                 '<a class="c-edit c-action" title="'+ editComment +'" alt="' + editComment + '">' + edit + '</a>' + " " +   
    42 								'<a class="c-delete c-action" title="'+ deleteComment +'" alt="' + deleteComment + '">' + del + '</a>' + " " +   
    42                 '<a class="c-delete c-action" title="'+ deleteComment +'" alt="' + deleteComment + '">' + del + '</a>' + " " +   
    43 							'</div>' +
    43               '</div>' +
    44 							'<div class="c-state-actions displaynone">' +
    44               '<div class="c-state-actions displaynone">' +
    45 								changeTo + '&nbsp;' +
    45                 changeTo + '&nbsp;' +
    46 								'<a class="c-state-pending c-action" title="' + changeToPending + '" alt="' + changeToPending + '">'+ pending +'</a>' + " " +  
    46                 '<a class="c-state-pending c-action" title="' + changeToPending + '" alt="' + changeToPending + '">'+ pending +'</a>' + " " +  
    47 								'<a class="c-state-approved c-action" title="' + changeToApprove + '" alt="' + changeToApprove + '">'+ approved +'</a>' + " " +  
    47                 '<a class="c-state-approved c-action" title="' + changeToApprove + '" alt="' + changeToApprove + '">'+ approved +'</a>' + " " +  
    48 								'<a class="c-state-unapproved c-action" title="' + changeToUnapprove + '" alt="' + changeToUnapprove + '">'+ unapproved +'</a>' + " " +  
    48                 '<a class="c-state-unapproved c-action" title="' + changeToUnapprove + '" alt="' + changeToUnapprove + '">'+ unapproved +'</a>' + " " +  
    49 								'<a class="c-state-cancel c-action" title="' + cancelChange + '" alt="' + cancelChange + '">' + cancel +'</a>' + " " +  
    49                 '<a class="c-state-cancel c-action" title="' + cancelChange + '" alt="' + cancelChange + '">' + cancel +'</a>' + " " +  
    50 							'</div>' + 
    50               '</div>' + 
    51 							'<div class="c-no-scope-msg">' +
    51               '<div class="c-no-scope-msg">' +
    52 								scopeRemoved +  
    52                 scopeRemoved +  
    53 							'</div>' + 
    53               '</div>' + 
    54 							'<a class="c-show-scope c-action" title="'+ showScope + '" alt="' + showScope + '"><em>-</em></a>' +
    54               '<a class="c-show-scope c-action" title="'+ showScope + '" alt="' + showScope + '"><em>-</em></a>' +
    55 							'<a class="c-close c-action" title="'+ close + '" alt="' + close + '"><em>X</em></a>' +
    55               '<a class="c-close c-action" title="'+ close + '" alt="' + close + '"><em>X</em></a>' +
    56 						'</div>',
    56             '</div>',
    57 		bodyContent :	'<div class="icomment-body">' +
    57     bodyContent : '<div class="icomment-body">' +
    58 						'<span class="c-content"></span>' +
    58             '<span class="c-content"></span>' +
    59 						'<span class="c-ireplyactions">' +
    59             '<span class="c-ireplyactions">' +
    60 						'<a class="c-readreplies c-action" title="'+ showReplies +'" alt="' + showReplies + '">' + showReplies +'</a>' + " " +  
    60             '<a class="c-readreplies c-action" title="'+ showReplies +'" alt="' + showReplies + '">' + showReplies +'</a>' + " " +  
    61 						'<a class="c-reply c-action" title="'+ reply +'" alt="' + reply + '">' + reply +'</a>' + "&nbsp;" +  
    61             '<a class="c-reply c-action" title="'+ reply +'" alt="' + reply + '">' + reply +'</a>' + "&nbsp;" +  
    62 						'</span>' +
    62             '</span>' +
    63 						'</div>'
    63             '</div>'
    64 	});
    64   });
    65 	
    65   
    66 	this.overlay.get('contentBox').addClass("c-comment") ;
    66   this.overlay.get('contentBox').addClass("c-comment") ;
    67 	
    67   
    68 	// attach to DOM
    68   // attach to DOM
    69 	this.overlay.render('#leftcolumn');
    69   this.overlay.render('#leftcolumn');
    70 	
    70   
    71 	this.animation = new CY.Anim({
    71   this.animation = new CY.Anim({
    72         node: this.overlay.get('boundingBox'),
    72         node: this.overlay.get('boundingBox'),
    73         duration: gPrefs.get('general','animduration'),
    73         duration: gPrefs.get('general','animduration'),
    74         easing: CY.Easing.easeOut
    74         easing: CY.Easing.easeOut
    75     });		
    75     });   
    76 
    76 
    77 	// CY.on won't work 
    77   // CY.on won't work 
    78 	this.overlay.get('contentBox').query(".c-close").on("click", this.onCloseCommentClick, this);
    78   this.overlay.get('contentBox').query(".c-close").on("click", this.onCloseCommentClick, this);
    79 	this.overlay.get('contentBox').query(".c-moderate").on("click", this.onModerateCommentClick, this);
    79   this.overlay.get('contentBox').query(".c-moderate").on("click", this.onModerateCommentClick, this);
    80 	this.overlay.get('contentBox').query(".c-state-pending").on("click", this.onPendingCommentClick, this);
    80   this.overlay.get('contentBox').query(".c-state-pending").on("click", this.onPendingCommentClick, this);
    81 	this.overlay.get('contentBox').query(".c-state-approved").on("click", this.onApprovedCommentClick, this);
    81   this.overlay.get('contentBox').query(".c-state-approved").on("click", this.onApprovedCommentClick, this);
    82 	this.overlay.get('contentBox').query(".c-state-unapproved").on("click", this.onUnapprovedCommentClick, this);
    82   this.overlay.get('contentBox').query(".c-state-unapproved").on("click", this.onUnapprovedCommentClick, this);
    83 	this.overlay.get('contentBox').query(".c-state-cancel").on("click", this.onCancelStateChangeClick, this);
    83   this.overlay.get('contentBox').query(".c-state-cancel").on("click", this.onCancelStateChangeClick, this);
    84 	this.overlay.get('contentBox').query(".c-edit").on("click", this.onEditCommentClick, this);
    84   this.overlay.get('contentBox').query(".c-edit").on("click", this.onEditCommentClick, this);
    85 	this.overlay.get('contentBox').query(".c-delete").on("click", this.onDeleteCommentClick, this);
    85   this.overlay.get('contentBox').query(".c-delete").on("click", this.onDeleteCommentClick, this);
    86 	this.overlay.get('contentBox').query(".c-reply").on("click", this.onReplyCommentClick, this);
    86   this.overlay.get('contentBox').query(".c-reply").on("click", this.onReplyCommentClick, this);
    87 	this.overlay.get('contentBox').query(".c-readreplies").on("click", this.onReadRepliesCommentClick, this);
    87   this.overlay.get('contentBox').query(".c-readreplies").on("click", this.onReadRepliesCommentClick, this);
    88 
    88 
    89 	this.overlay.get('contentBox').query(".icomment-header").on("mouseenter", this.onMouseEnterHeader, this);
    89   this.overlay.get('contentBox').query(".icomment-header").on("mouseenter", this.onMouseEnterHeader, this);
    90 	this.overlay.get('contentBox').query(".icomment-header").on("mouseleave", this.onMouseLeaveHeader, this);
    90   this.overlay.get('contentBox').query(".icomment-header").on("mouseleave", this.onMouseLeaveHeader, this);
    91 	
    91   
    92 	this.overlay.get('contentBox').on("click", this.onCommentClick, this);
    92   this.overlay.get('contentBox').on("click", this.onCommentClick, this);
    93 }
    93 }
    94 
    94 
    95 IComment.prototype = {
    95 IComment.prototype = {
    96 	// checking readyForAction is not enough because handler could be called after animation end in the case : 
    96   // checking readyForAction is not enough because handler could be called after animation end in the case : 
    97 	// close btn is clicked before animation end (so before overlay gets hidden) but handler is called after so preventClickOn is false and close is called on an invisible overlay.
    97   // close btn is clicked before animation end (so before overlay gets hidden) but handler is called after so preventClickOn is false and close is called on an invisible overlay.
    98 	// (whan clicking very fast on the close button while close animation is taking place).
    98   // (whan clicking very fast on the close button while close animation is taking place).
    99 	// SO : SHOULD ALWAYS CHECK FOR VISIBLE OVERLAY IN HANDLERS THAT COULD BE CALLED FROM AN ANIMATED OVERLAY
    99   // SO : SHOULD ALWAYS CHECK FOR VISIBLE OVERLAY IN HANDLERS THAT COULD BE CALLED FROM AN ANIMATED OVERLAY
   100 	onCloseCommentClick : function (e) {
   100   onCloseCommentClick : function (e) {
   101 		e.halt() ; // prevent click triggered on content box
   101     e.halt() ; // prevent click triggered on content box
   102 		if (readyForAction() && this.isVisible()) 
   102     if (readyForAction() && this.isVisible()) 
   103 			gSync.closeComment(this) ;
   103       gSync.closeComment(this) ;
   104 	},
   104   },
   105 	onModerateCommentClick : function (e) {
   105   onModerateCommentClick : function (e) {
   106 		e.halt() ; // prevent click triggered on content box
   106     e.halt() ; // prevent click triggered on content box
   107 		if (readyForAction() && this.isVisible()) {
   107     if (readyForAction() && this.isVisible()) {
   108 			this.overlay.get('contentBox').query(".c-iactions").addClass("displaynone") ;
   108       this.overlay.get('contentBox').query(".c-iactions").addClass("displaynone") ;
   109 			this.overlay.get('contentBox').query(".c-state-actions").removeClass("displaynone") ;
   109       this.overlay.get('contentBox').query(".c-state-actions").removeClass("displaynone") ;
   110 		}
   110     }
   111 	},
   111   },
   112 	onPendingCommentClick : function (e) {
   112   onPendingCommentClick : function (e) {
   113 		e.halt() ; // prevent click triggered on content box
   113     e.halt() ; // prevent click triggered on content box
   114 		if (readyForAction() && this.isVisible()) {
   114     if (readyForAction() && this.isVisible()) {
   115 			gSync.moderateComment(this, 'pending') ;
   115       gSync.moderateComment(this, 'pending') ;
   116 		}
   116     }
   117 	},
   117   },
   118 	onApprovedCommentClick : function (e) {
   118   onApprovedCommentClick : function (e) {
   119 		e.halt() ; // prevent click triggered on content box
   119     e.halt() ; // prevent click triggered on content box
   120 		if (readyForAction() && this.isVisible()) {
   120     if (readyForAction() && this.isVisible()) {
   121 			gSync.moderateComment(this, 'approved') ;
   121       gSync.moderateComment(this, 'approved') ;
   122 		}
   122     }
   123 	},
   123   },
   124 	onUnapprovedCommentClick : function (e) {
   124   onUnapprovedCommentClick : function (e) {
   125 		e.halt() ; // prevent click triggered on content box
   125     e.halt() ; // prevent click triggered on content box
   126 		if (readyForAction() && this.isVisible()) {
   126     if (readyForAction() && this.isVisible()) {
   127 			gSync.moderateComment(this, 'unapproved') ;
   127       gSync.moderateComment(this, 'unapproved') ;
   128 		}
   128     }
   129 	},
   129   },
   130 	onCancelStateChangeClick : function (e) {
   130   onCancelStateChangeClick : function (e) {
   131 		e.halt() ; // prevent click triggered on content box
   131     e.halt() ; // prevent click triggered on content box
   132 		if (readyForAction() && this.isVisible()) {
   132     if (readyForAction() && this.isVisible()) {
   133 			this.overlay.get('contentBox').query(".c-iactions").removeClass("displaynone") ;
   133       this.overlay.get('contentBox').query(".c-iactions").removeClass("displaynone") ;
   134 			this.overlay.get('contentBox').query(".c-state-actions").addClass("displaynone") ;
   134       this.overlay.get('contentBox').query(".c-state-actions").addClass("displaynone") ;
   135 		}
   135     }
   136 	},
   136   },
   137 	onDeleteCommentClick : function (e) {
   137   onDeleteCommentClick : function (e) {
   138 		e.halt() ; // prevent click triggered on content box
   138     e.halt() ; // prevent click triggered on content box
   139 		if (readyForAction() && this.isVisible()) {
   139     if (readyForAction() && this.isVisible()) {
   140 			gSync.removeComment(this) ;
   140       gSync.removeComment(this) ;
   141 		}
   141     }
   142 	},
   142   },
   143 	onEditCommentClick : function (e) {
   143   onEditCommentClick : function (e) {
   144 		e.halt() ; // prevent click triggered on content box
   144     e.halt() ; // prevent click triggered on content box
   145 		if (readyForAction() && this.isVisible()) 
   145     if (readyForAction() && this.isVisible()) 
   146 			gSync.showEditForm(this) ;
   146       gSync.showEditForm(this) ;
   147 	},
   147   },
   148 	onReplyCommentClick : function (e) {
   148   onReplyCommentClick : function (e) {
   149 		e.halt() ; // prevent click triggered on content box
   149     e.halt() ; // prevent click triggered on content box
   150 		if (readyForAction() && this.isVisible()) 
   150     if (readyForAction() && this.isVisible()) 
   151 			gSync.showReplyForm(this) ;
   151       gSync.showReplyForm(this) ;
   152 	},
   152   },
   153 	onReadRepliesCommentClick : function (e) {
   153   onReadRepliesCommentClick : function (e) {
   154 		e.halt() ; // prevent click triggered on content box
   154     e.halt() ; // prevent click triggered on content box
   155 		if (readyForAction() && this.isVisible()) 
   155     if (readyForAction() && this.isVisible()) 
   156 			gSync.openComment(this) ;
   156       gSync.openComment(this) ;
   157 	},
   157   },
   158 	onCommentClick : function (e) {
   158   onCommentClick : function (e) {
   159 		if (readyForAction() && this.isVisible()) {
   159     if (readyForAction() && this.isVisible()) {
   160 			// first condition here is checking it's not clicked via a 'show comments' 	link
   160       // first condition here is checking it's not clicked via a 'show comments'  link
   161 			if (e.target.get("target") == "_blank") {
   161       if (e.target.get("target") == "_blank") {
   162 				var link = e.target ;
   162         var link = e.target ;
   163 				var showCommentUrl = sv_site_url + sv_text_view_show_comment_url ;
   163         var showCommentUrl = sv_site_url + sv_text_view_show_comment_url ;
   164 				if (link.get('href').indexOf(showCommentUrl) == 0) { 
   164         if (link.get('href').indexOf(showCommentUrl) == 0) { 
   165 					var res = (new RegExp('comment_id_key=([^&]*)', "g")).exec(link.get('href')) ;
   165           var res = (new RegExp('comment_id_key=([^&]*)', "g")).exec(link.get('href')) ;
   166 					if (res != null) {
   166           if (res != null) {
   167 						// open new comment .... we'll suppose it satisfies the filter for now
   167             // open new comment .... we'll suppose it satisfies the filter for now
   168 						// TODO : should we reset the filter in this case ? instead of having the link open in a new window
   168             // TODO : should we reset the filter in this case ? instead of having the link open in a new window
   169 						var id_key = res[1] ;
   169             var id_key = res[1] ;
   170 						var comment = gDb.getCommentByIdKey(id_key) ;
   170             var comment = gDb.getCommentByIdKey(id_key) ;
   171 						if (comment != null) {
   171             if (comment != null) {
   172 							e.halt() ;
   172               e.halt() ;
   173 							if (!link.hasClass("c-permalink")) {// clicking on the permalink itself should do anything
   173               if (!link.hasClass("c-permalink")) {// clicking on the permalink itself should do anything
   174 								checkForOpenedDialog(null, function() {
   174                 checkForOpenedDialog(null, function() {
   175 									gSync.showSingleComment(comment) ;
   175                   gSync.showSingleComment(comment) ;
   176 								}) ;
   176                 }) ;
   177 							}
   177               }
   178 						}
   178             }
   179 					}
   179           }
   180 				}
   180         }
   181 			}
   181       }
   182 			else {
   182       else {
   183 				if (gShowingAllComments) {
   183         if (gShowingAllComments) {
   184 					// next special dirty case test explained : when editing/replying to a comment with gShowingAllComments a click in the edit/reply form also is a click on the iComment, in this case we don't want to showSingleComment ....
   184           // next special dirty case test explained : when editing/replying to a comment with gShowingAllComments a click in the edit/reply form also is a click on the iComment, in this case we don't want to showSingleComment ....
   185 					// should be handled via a preventDefault in some way
   185           // should be handled via a preventDefault in some way
   186 					if (!this._isHostingAForm()) {
   186           if (!this._isHostingAForm()) {
   187 						var comment = gDb.getComment(this.commentId) ;
   187             var comment = gDb.getComment(this.commentId) ;
   188 						checkForOpenedDialog(null, function() {
   188             checkForOpenedDialog(null, function() {
   189 							if (comment != null) 
   189               if (comment != null) 
   190 								gSync.showSingleComment(comment) ;
   190                 gSync.showSingleComment(comment) ;
   191 						})
   191             })
   192 					}
   192           }
   193 				}
   193         }
   194 				else 
   194         else 
   195 					gSync.activate(this) ;
   195           gSync.activate(this) ;
   196 			}
   196       }
   197 		}
   197     }
   198 	},	
   198   },  
   199 	
   199   
   200 	onMouseEnterHeader : function () {
   200   onMouseEnterHeader : function () {
   201 		if (readyForAction() && this.isVisible() && (sv_prefix=="")) {
   201     if (readyForAction() && this.isVisible() && (sv_prefix=="")) {
   202 			this.overlay.get('contentBox').query(".c-permalink").removeClass('displaynone');
   202       this.overlay.get('contentBox').query(".c-permalink").removeClass('displaynone');
   203 		}
   203     }
   204 	},
   204   },
   205 	
   205   
   206 	onMouseLeaveHeader : function () {
   206   onMouseLeaveHeader : function () {
   207 		if (readyForAction() && this.isVisible() && (sv_prefix=="")) {
   207     if (readyForAction() && this.isVisible() && (sv_prefix=="")) {
   208 			this.overlay.get('contentBox').query(".c-permalink").addClass('displaynone');
   208       this.overlay.get('contentBox').query(".c-permalink").addClass('displaynone');
   209 		}
   209     }
   210 	},	
   210   },  
   211 	
   211   
   212 	setWidth : function(width) {
   212   setWidth : function(width) {
   213 	    this.overlay.get('boundingBox').setStyle("width", width + 'px');
   213       this.overlay.get('boundingBox').setStyle("width", width + 'px');
   214 	},
   214   },
   215 	
   215   
   216 	activate:function() {
   216   activate:function() {
   217 		// debug !!
   217     // debug !!
   218 //		CY.log('activate' + this.commentId) ;
   218 //    CY.log('activate' + this.commentId) ;
   219 		this.overlay.get('boundingBox').addClass('c-focus-comment') ;
   219     this.overlay.get('boundingBox').addClass('c-focus-comment') ;
   220 		
   220     
   221 	},
   221   },
   222 	
   222   
   223 	deactivate:function() {
   223   deactivate:function() {
   224 		// debug !!
   224     // debug !!
   225 //		CY.log('deactivate' + this.commentId) ;
   225 //    CY.log('deactivate' + this.commentId) ;
   226 		this.overlay.get('boundingBox').removeClass('c-focus-comment') ;
   226     this.overlay.get('boundingBox').removeClass('c-focus-comment') ;
   227 		
   227     
   228 	},
   228   },
   229 	hide:function() {
   229   hide:function() {
   230 		// is IComment the top active one ?
   230     // is IComment the top active one ?
   231 		if (gIComments.isTopActive(this.commentId)) { // then try to activate next in displayed list
   231     if (gIComments.isTopActive(this.commentId)) { // then try to activate next in displayed list
   232 			if (!gIComments.activateVisibleNext())
   232       if (!gIComments.activateVisibleNext())
   233 				gIComments.deactivate() ;
   233         gIComments.deactivate() ;
   234 		}
   234     }
   235 
   235 
   236 		if (this.isVisible()) {
   236     if (this.isVisible()) {
   237 			this.overlay.hide();
   237       this.overlay.hide();
   238 			this.overlay.blur() ;
   238       this.overlay.blur() ;
   239 		}
   239     }
   240 	},
   240   },
   241 	hideContent:function() {
   241   hideContent:function() {
   242 		this.overlay.get('contentBox').query(".icomment-header").addClass('displaynone') ;
   242     this.overlay.get('contentBox').query(".icomment-header").addClass('displaynone') ;
   243 		this.overlay.get('contentBox').query(".icomment-body").addClass('displaynone') ;
   243     this.overlay.get('contentBox').query(".icomment-body").addClass('displaynone') ;
   244 	},
   244   },
   245 	showContent:function() {
   245   showContent:function() {
   246 		this.overlay.get('contentBox').query(".icomment-header").removeClass('displaynone') ;
   246     this.overlay.get('contentBox').query(".icomment-header").removeClass('displaynone') ;
   247 		this.overlay.get('contentBox').query(".icomment-body").removeClass('displaynone') ;
   247     this.overlay.get('contentBox').query(".icomment-body").removeClass('displaynone') ;
   248 	},
   248   },
   249 	isVisible:function() {
   249   isVisible:function() {
   250 		return this.overlay.get('visible') ;
   250     return this.overlay.get('visible') ;
   251 	},
   251   },
   252 	show:function() {
   252   show:function() {
   253 		this.hideReadRepliesLnk() ; // for now
   253     this.hideReadRepliesLnk() ; // for now
   254 		return this.overlay.show() ;
   254     return this.overlay.show() ;
   255 	},
   255   },
   256 	showReadRepliesLnk:function() {
   256   showReadRepliesLnk:function() {
   257 		this.overlay.get('contentBox').query(".c-readreplies").removeClass('displaynone') ;
   257     this.overlay.get('contentBox').query(".c-readreplies").removeClass('displaynone') ;
   258 	},
   258   },
   259 	hideReadRepliesLnk:function() {
   259   hideReadRepliesLnk:function() {
   260 		this.overlay.get('contentBox').query(".c-readreplies").addClass('displaynone') ;
   260     this.overlay.get('contentBox').query(".c-readreplies").addClass('displaynone') ;
   261 	},
   261   },
   262 	changeModeration:function(comment) {
   262   changeModeration:function(comment) {
   263 		var moderationLnk = this.overlay.get('contentBox').query(".c-moderate") ;
   263     var moderationLnk = this.overlay.get('contentBox').query(".c-moderate") ;
   264 		moderationLnk.set("innerHTML", gettext(comment.state)) ;
   264     moderationLnk.set("innerHTML", gettext(comment.state)) ;
   265 		
   265     
   266 		moderationLnk.removeClass("c-state-approved") ;
   266     moderationLnk.removeClass("c-state-approved") ;
   267 		moderationLnk.removeClass("c-state-pending") ;
   267     moderationLnk.removeClass("c-state-pending") ;
   268 		moderationLnk.removeClass("c-state-unapproved") ;
   268     moderationLnk.removeClass("c-state-unapproved") ;
   269 		moderationLnk.addClass("c-state-" + comment.state) ;
   269     moderationLnk.addClass("c-state-" + comment.state) ;
   270 
   270 
   271 		this.overlay.get('contentBox').query(".c-iactions").removeClass("displaynone") ;
   271     this.overlay.get('contentBox').query(".c-iactions").removeClass("displaynone") ;
   272 		this.overlay.get('contentBox').query(".c-state-actions").addClass("displaynone") ;
   272     this.overlay.get('contentBox').query(".c-state-actions").addClass("displaynone") ;
   273 	},
   273   },
   274 	isfetched : function() {
   274   isfetched : function() {
   275 		return (this.commentId != null) ;
   275     return (this.commentId != null) ;
   276 	},
   276   },
   277 	unfetch : function() {
   277   unfetch : function() {
   278 		this.commentId = null ;
   278     this.commentId = null ;
   279 	},
   279   },
   280 	fetch : function(comment) {
   280   fetch : function(comment) {
   281 		this.commentId = comment.id ;
   281     this.commentId = comment.id ;
   282 		var boundingBoxNode = this.overlay.get('boundingBox') ;
   282     var boundingBoxNode = this.overlay.get('boundingBox') ;
   283 		
   283     
   284 		if (comment['start_wrapper'] != -1){ 
   284     if (comment['start_wrapper'] != -1){ 
   285 			boundingBoxNode.addClass('c-has-scope') ;
   285       boundingBoxNode.addClass('c-has-scope') ;
   286 			boundingBoxNode.removeClass('c-has-no-scope') ;
   286       boundingBoxNode.removeClass('c-has-no-scope') ;
   287 		}
   287     }
   288 		else { 
   288     else { 
   289 			boundingBoxNode.addClass('c-has-no-scope') ;
   289       boundingBoxNode.addClass('c-has-no-scope') ;
   290 			boundingBoxNode.removeClass('c-has-scope') ;
   290       boundingBoxNode.removeClass('c-has-scope') ;
   291 		}
   291     }
   292 		
   292     
   293 		if (comment['reply_to_id'] != null){ 
   293     if (comment['reply_to_id'] != null){ 
   294 			boundingBoxNode.addClass('c-is-reply') ;
   294       boundingBoxNode.addClass('c-is-reply') ;
   295 		}
   295     }
   296 		else { 
   296     else { 
   297 			boundingBoxNode.removeClass('c-is-reply') ;
   297       boundingBoxNode.removeClass('c-is-reply') ;
   298 		}
   298     }
   299 		
   299     
   300 		// TITLE
   300     // TITLE
   301 		var titleInfos = interpolate(gettext('last modified on %(date)s'),{'date':comment.modified_user_str}, true) ;
   301     var titleInfos = interpolate(gettext('last modified on %(date)s'),{'date':comment.modified_user_str}, true) ;
   302 		
   302     
   303 		var modifDateTooltip = (comment.modified == comment.created) ? '' : '<a title="' + titleInfos + '"> * </a>' ;
   303     var modifDateTooltip = (comment.modified == comment.created) ? '' : '<a title="' + titleInfos + '"> * </a>' ;
   304 		var permaTitle = gettext('Permalink to this comment') ;
   304     var permaTitle = gettext('Permalink to this comment') ;
   305 		var permalink = "";
   305     var permalink = "";
   306 		if (sv_prefix=="") {
   306     if (sv_prefix=="") {
   307 			permalink = '<a class="c-permalink displaynone c-action" target="_blank" title="'+ permaTitle +'" href="" >¶&nbsp;</a>' ;
   307       permalink = '<a class="c-permalink displaynone c-action" target="_blank" title="'+ permaTitle +'" href="" >¶&nbsp;</a>' ;
   308 		}
   308     }
   309 		
   309     
   310 		var infos = interpolate(gettext('by %(name)s, created on %(date)s'),{'name':comment.name, 'date':comment.created_user_str}, true) ;
   310     var infos = interpolate(gettext('by %(name)s, created on %(date)s'),{'name':comment.name, 'date':comment.created_user_str}, true) ;
   311 		
   311     
   312 		var newTitleContent = '<span class="c-header"><div class="c-header-title">' + comment.title + permalink + '</div><div class="c-infos">' + infos + '</div></span>' ;
   312     var newTitleContent = '<span class="c-header"><div class="c-header-title">' + comment.title + permalink + '</div><div class="c-infos">' + infos + '</div></span>' ;
   313 		
   313     
   314 		var newTitleNode = CY.Node.create(newTitleContent) ;
   314     var newTitleNode = CY.Node.create(newTitleContent) ;
   315 		var prevTitleNode = boundingBoxNode.query(".c-header") ;
   315     var prevTitleNode = boundingBoxNode.query(".c-header") ;
   316 		if (prevTitleNode == null) // first time, no title yet
   316     if (prevTitleNode == null) // first time, no title yet
   317 			boundingBoxNode.query('.icomment-header').insertBefore(newTitleNode, boundingBoxNode.one('.c-iactions')) ;
   317       boundingBoxNode.query('.icomment-header').insertBefore(newTitleNode, boundingBoxNode.one('.c-iactions')) ;
   318 		else 
   318     else 
   319 			prevTitleNode.get('parentNode').replaceChild(newTitleNode, prevTitleNode) ;
   319       prevTitleNode.get('parentNode').replaceChild(newTitleNode, prevTitleNode) ;
   320 
   320 
   321 		// TAG
   321     // TAG
   322 		var newTagNode = CY.Node.create('<div class="c-tags"><span class="c-tags-infos">' + 'tags:' + '</span>' + comment.tags + '</div>') ;
   322     var newTagNode = CY.Node.create('<div class="c-tags"><span class="c-tags-infos">' + 'tags:' + '</span>' + comment.tags + '</div>') ;
   323 		var prevTagNode = boundingBoxNode.query(".c-tags") ;
   323     var prevTagNode = boundingBoxNode.query(".c-tags") ;
   324 		if (prevTagNode == null) 
   324     if (prevTagNode == null) 
   325 			boundingBoxNode.query('.icomment-header').appendChild(newTagNode) ;
   325       boundingBoxNode.query('.icomment-header').appendChild(newTagNode) ;
   326 		else 
   326     else 
   327 			prevTagNode.get('parentNode').replaceChild(newTagNode, prevTagNode) ;
   327       prevTagNode.get('parentNode').replaceChild(newTagNode, prevTagNode) ;
   328 		// NO TAG ?
   328     // NO TAG ?
   329 		if (comment.tags == "")
   329     if (comment.tags == "")
   330 			newTagNode.addClass('displaynone') ;
   330       newTagNode.addClass('displaynone') ;
   331 
   331 
   332 		// CONTENT
   332     // CONTENT
   333 		var newContentNode = CY.Node.create('<span class="c-content">' + comment.content_html + '</span>') ;
   333     var newContentNode = CY.Node.create('<span class="c-content">' + comment.content_html + '</span>') ;
   334 		var prevContentNode = boundingBoxNode.query(".c-content") ;
   334     var prevContentNode = boundingBoxNode.query(".c-content") ;
   335 		if (prevContentNode == null) 
   335     if (prevContentNode == null) 
   336 			boundingBoxNode.query('.icomment-body').appendChild(newContentNode) ;
   336       boundingBoxNode.query('.icomment-body').appendChild(newContentNode) ;
   337 		else 
   337     else 
   338 			prevContentNode.get('parentNode').replaceChild(newContentNode, prevContentNode) ;
   338       prevContentNode.get('parentNode').replaceChild(newContentNode, prevContentNode) ;
   339 
   339 
   340 		// PERMALINK
   340     // PERMALINK
   341 		if (sv_prefix=="") {
   341     if (sv_prefix=="") {
   342 			boundingBoxNode.query(".c-permalink").set("href",sv_site_url + comment.permalink) ;
   342       boundingBoxNode.query(".c-permalink").set("href",sv_site_url + comment.permalink) ;
   343 		}
   343     }
   344 
   344 
   345 		// MODERATION
   345     // MODERATION
   346 		this.changeModeration(comment) ;
   346     this.changeModeration(comment) ;
   347 /* useless : use implemendted permanentlink instead
   347 /* useless : use implemendted permanentlink instead
   348  * 
   348  * 
   349 		// also change link title to give users the possibility to know comment id (to be able to reference this exact comment in GET arguments) 
   349     // also change link title to give users the possibility to know comment id (to be able to reference this exact comment in GET arguments) 
   350 		var moderationLnk = this.overlay.get('contentBox').query(".c-moderate") ;
   350     var moderationLnk = this.overlay.get('contentBox').query(".c-moderate") ;
   351 		//var cid = (comment.reply_to_id == null) ? this.commentId : "" ;
   351     //var cid = (comment.reply_to_id == null) ? this.commentId : "" ;
   352 		moderationLnk.set("title", "click to change comment ID visibility".replace(/ID/, this.commentId).replace(/  /, " ")) ;
   352     moderationLnk.set("title", "click to change comment ID visibility".replace(/ID/, this.commentId).replace(/  /, " ")) ;
   353 		
   353     
   354  */		
   354  */   
   355 		// open links in new window :
   355     // open links in new window :
   356 		var links = boundingBoxNode.queryAll(".c-content a") ;
   356     var links = boundingBoxNode.queryAll(".c-content a") ;
   357 		if (links != null)
   357     if (links != null)
   358 			links.setAttribute( "target" , "_blank" ) ;
   358       links.setAttribute( "target" , "_blank" ) ;
   359 		links = boundingBoxNode.queryAll(".c-header-title a") ;
   359     links = boundingBoxNode.queryAll(".c-header-title a") ;
   360 		if (links != null)
   360     if (links != null)
   361 			links.setAttribute( "target" , "_blank" ) ;
   361       links.setAttribute( "target" , "_blank" ) ;
   362 		
   362     
   363 		this.permAdapt(comment) ;
   363     this.permAdapt(comment) ;
   364 	},
   364   },
   365 
   365 
   366 	permAdapt : function(comment) {
   366   permAdapt : function(comment) {
   367 		// this comment permissions 
   367     // this comment permissions 
   368 		var delLnk = this.overlay.get('contentBox').query(".c-delete") ; 
   368     var delLnk = this.overlay.get('contentBox').query(".c-delete") ; 
   369 		if (delLnk) {	// there will be a server side check anyway
   369     if (delLnk) { // there will be a server side check anyway
   370 			if (!comment.can_delete)
   370       if (!comment.can_delete)
   371 				delLnk.addClass('displaynone') ;
   371         delLnk.addClass('displaynone') ;
   372 			else 
   372       else 
   373 				delLnk.removeClass('displaynone') ;
   373         delLnk.removeClass('displaynone') ;
   374 		}
   374     }
   375 
   375 
   376 		var editLnk = this.overlay.get('contentBox').query(".c-edit") ; 
   376     var editLnk = this.overlay.get('contentBox').query(".c-edit") ; 
   377 		if (editLnk) {	
   377     if (editLnk) {  
   378 			if (!comment.can_edit) 
   378       if (!comment.can_edit) 
   379 				editLnk.addClass('displaynone') ;
   379         editLnk.addClass('displaynone') ;
   380 			else 
   380       else 
   381 				editLnk.removeClass('displaynone') ;
   381         editLnk.removeClass('displaynone') ;
   382 		}
   382     }
   383 		
   383     
   384 		var replyLnk = this.overlay.get('contentBox').query(".c-reply") ;
   384     var replyLnk = this.overlay.get('contentBox').query(".c-reply") ;
   385 		if (replyLnk) {
   385     if (replyLnk) {
   386 			if (!hasPerm("can_create_comment"))
   386       if (!hasPerm("can_create_comment"))
   387 				replyLnk.addClass('displaynone') ;
   387         replyLnk.addClass('displaynone') ;
   388 			else 
   388       else 
   389 				replyLnk.removeClass('displaynone') ;
   389         replyLnk.removeClass('displaynone') ;
   390 		}
   390     }
   391 
   391 
   392 		var moderateLnk = this.overlay.get('contentBox').query(".c-moderate") ; 
   392     var moderateLnk = this.overlay.get('contentBox').query(".c-moderate") ; 
   393 		if (moderateLnk) {	
   393     if (moderateLnk) {  
   394 			if (!comment.can_moderate)  
   394       if (!comment.can_moderate)  
   395 				moderateLnk.addClass('displaynone') ;
   395         moderateLnk.addClass('displaynone') ;
   396 			else 
   396       else 
   397 				moderateLnk.removeClass('displaynone') ;
   397         moderateLnk.removeClass('displaynone') ;
   398 		}
   398     }
   399 	},
   399   },
   400 	setThreadPad : function(pad) { // TODO review ...
   400   setThreadPad : function(pad) { // TODO review ...
   401 		this.overlay.get('contentBox').query('.yui-widget-hd').setStyle('paddingLeft', pad + 'px') ;
   401     this.overlay.get('contentBox').query('.yui-widget-hd').setStyle('paddingLeft', pad + 'px') ;
   402 		this.overlay.get('contentBox').query('.yui-widget-bd').setStyle('paddingLeft', pad + 'px') ;
   402     this.overlay.get('contentBox').query('.yui-widget-bd').setStyle('paddingLeft', pad + 'px') ;
   403 		
   403     
   404 	},
   404   },
   405 	setPosition : function(xy) {
   405   setPosition : function(xy) {
   406 		var boundingBoxNode = this.overlay.get('boundingBox') ;
   406     var boundingBoxNode = this.overlay.get('boundingBox') ;
   407 
   407 
   408 	    boundingBoxNode.setStyle("opacity", 1); // TODO check this is still usefull
   408       boundingBoxNode.setStyle("opacity", 1); // TODO check this is still usefull
   409 	   	boundingBoxNode.setXY(xy) ;
   409       boundingBoxNode.setXY(xy) ;
   410 	},
   410   },
   411 	getPosition : function(xy) {
   411   getPosition : function(xy) {
   412 		var boundingBoxNode = this.overlay.get('boundingBox') ;
   412     var boundingBoxNode = this.overlay.get('boundingBox') ;
   413 
   413 
   414 	   	return boundingBoxNode.getXY() ;
   414       return boundingBoxNode.getXY() ;
   415 	},
   415   },
   416 	onAnimationEnd : function() {
   416   onAnimationEnd : function() {
   417 		if (!CY.Lang.isUndefined(this['animation-handle']) && !CY.Lang.isNull(this['animation-handle'])) { 
   417     if (!CY.Lang.isUndefined(this['animation-handle']) && !CY.Lang.isNull(this['animation-handle'])) { 
   418 			this['animation-handle'].detach() ;
   418       this['animation-handle'].detach() ;
   419 			this['animation-handle'] = null ;
   419       this['animation-handle'] = null ;
   420 //			CY.log('detached...') ;
   420 //      CY.log('detached...') ;
   421 		}
   421     }
   422 		gIComments.signalAnimationEnd() ;
   422     gIComments.signalAnimationEnd() ;
   423 		if (gIComments.animationsEnded())
   423     if (gIComments.animationsEnded())
   424 			gIComments.whenAnimationsEnd() ;		
   424       gIComments.whenAnimationsEnd() ;    
   425 	},
   425   },
   426 	onAnimationEndFocus : function() {
   426   onAnimationEndFocus : function() {
   427 		if (!CY.Lang.isUndefined(this['animation-handle']) && !CY.Lang.isNull(this['animation-handle'])) { 
   427     if (!CY.Lang.isUndefined(this['animation-handle']) && !CY.Lang.isNull(this['animation-handle'])) { 
   428 			this['animation-handle'].detach() ;
   428       this['animation-handle'].detach() ;
   429 			this['animation-handle'] = null ;
   429       this['animation-handle'] = null ;
   430 //			CY.log('detached...') ;
   430 //      CY.log('detached...') ;
   431 		}
   431     }
   432 		gIComments.signalAnimationEnd() ;
   432     gIComments.signalAnimationEnd() ;
   433 		if (gIComments.animationsEnded())
   433     if (gIComments.animationsEnded())
   434 			gIComments.whenAnimationsEndFocus() ;		
   434       gIComments.whenAnimationsEndFocus() ;   
   435 	},
   435   },
   436 	onAnimationEndReply : function() {
   436   onAnimationEndReply : function() {
   437 		if (!CY.Lang.isUndefined(this['animation-handle']) && !CY.Lang.isNull(this['animation-handle'])) { 
   437     if (!CY.Lang.isUndefined(this['animation-handle']) && !CY.Lang.isNull(this['animation-handle'])) { 
   438 			this['animation-handle'].detach() ;
   438       this['animation-handle'].detach() ;
   439 			this['animation-handle'] = null ;
   439       this['animation-handle'] = null ;
   440 //			CY.log('detached...') ;
   440 //      CY.log('detached...') ;
   441 		}
   441     }
   442 		gIComments.signalAnimationEnd() ;
   442     gIComments.signalAnimationEnd() ;
   443 		if (gIComments.animationsEnded())
   443     if (gIComments.animationsEnded())
   444 			gIComments.whenAnimationsEndReply() ;		
   444       gIComments.whenAnimationsEndReply() ;   
   445 	},
   445   },
   446 
   446 
   447 	//aa = new CY.Anim({node:gIComments._c[0].overlay.get('boundingBox'), to:{xy : [0,0]}, duration:2.0})
   447   //aa = new CY.Anim({node:gIComments._c[0].overlay.get('boundingBox'), to:{xy : [0,0]}, duration:2.0})
   448 	setAnimationToPosition : function(toXY, focus, reply) {
   448   setAnimationToPosition : function(toXY, focus, reply) {
   449 		var boundingBoxNode = this.overlay.get('boundingBox') ;
   449     var boundingBoxNode = this.overlay.get('boundingBox') ;
   450 		
   450     
   451 		// ANIMATION
   451     // ANIMATION
   452 	    // 2 lines of optim that could be removed (0.011)
   452       // 2 lines of optim that could be removed (0.011)
   453 		if (gPrefs.get('general','animduration') < 0.011) 
   453     if (gPrefs.get('general','animduration') < 0.011) 
   454 	    	boundingBoxNode.setXY(toXY) ;
   454         boundingBoxNode.setXY(toXY) ;
   455 		
   455     
   456 		this.animation.set('to', { xy: toXY});
   456     this.animation.set('to', { xy: toXY});
   457 		this.animation.set('duration', gPrefs.get('general','animduration')) ; // shouldn't be here really ...
   457     this.animation.set('duration', gPrefs.get('general','animduration')) ; // shouldn't be here really ...
   458     if (focus)
   458     if (focus)
   459       if (reply)
   459       if (reply)
   460     	  this['animation-handle'] = this.animation.on('end', this.onAnimationEndReply, this);
   460         this['animation-handle'] = this.animation.on('end', this.onAnimationEndReply, this);
   461       else
   461       else
   462     	  this['animation-handle'] = this.animation.on('end', this.onAnimationEndFocus, this);
   462         this['animation-handle'] = this.animation.on('end', this.onAnimationEndFocus, this);
   463     else
   463     else
   464     	this['animation-handle'] = this.animation.on('end', this.onAnimationEnd, this);
   464       this['animation-handle'] = this.animation.on('end', this.onAnimationEnd, this);
   465 		
   465     
   466 		return this.animation ;
   466     return this.animation ;
   467 	},
   467   },
   468 	getHeight : function() {
   468   getHeight : function() {
   469 		return this.overlay.get('boundingBox').get('offsetHeight') ;
   469     return this.overlay.get('boundingBox').get('offsetHeight') ;
   470 	},
   470   },
   471 	scrollIntoView : function() {
   471   scrollIntoView : function() {
   472 		//this.isVisible() && 
   472     //this.isVisible() && 
   473 		if (!this.overlay.get('contentBox').inViewportRegion())
   473     if (!this.overlay.get('contentBox').inViewportRegion())
   474 			this.overlay.get('contentBox').scrollIntoView(true) ;
   474       this.overlay.get('contentBox').scrollIntoView(true) ;
   475 	},
   475   },
   476 	_isHostingAForm : function() {
   476   _isHostingAForm : function() {
   477 		return (this.isVisible() && ((gNewReplyHost != null && gNewReplyHost == this) || (gEditICommentHost != null && gEditICommentHost == this)));
   477     return (this.isVisible() && ((gNewReplyHost != null && gNewReplyHost == this) || (gEditICommentHost != null && gEditICommentHost == this)));
   478 	}
   478   }
   479 
   479 
   480 }
   480 }