|
1 gShowingAllComments = false ; |
|
2 // YUI : queue, overlay |
|
3 Sync = function() { |
|
4 // this queue handles both animations and io requests |
|
5 this._q = null ; |
|
6 |
|
7 this._iPreventClick = false ; // oh really ? |
|
8 } |
|
9 |
|
10 Sync.prototype = { |
|
11 init : function (iComment) { |
|
12 this._q = new CY.AsyncQueue() ; |
|
13 // pr2 this._q = new CY.Queue() ; |
|
14 }, |
|
15 |
|
16 setPreventClickOn : function () { |
|
17 CY.log("setPreventClickOn !") ; |
|
18 if (gLayout.isInFrame()) |
|
19 parent.f_interfaceFreeze() |
|
20 this._iPreventClick = true ; |
|
21 }, |
|
22 |
|
23 setPreventClickOff : function () { |
|
24 CY.log("setPreventClickOff !") ; |
|
25 if (gLayout.isInFrame()) |
|
26 parent.f_interfaceUnfreeze() |
|
27 this._iPreventClick = false ; |
|
28 }, |
|
29 |
|
30 removeCommentRet : function(args) { |
|
31 var successfull = args['successfull'] ; |
|
32 |
|
33 var iComment = (successfull) ? args['failure']['iComment'] : args['success']['iComment'] ; |
|
34 |
|
35 if (successfull) { |
|
36 var filterData = args['returned']['filterData'] ; |
|
37 if (gLayout.isInFrame()) { |
|
38 parent.f_updateFilterData(filterData) ; |
|
39 } |
|
40 |
|
41 var y = gIComments.getTopPosition()[1] ; |
|
42 |
|
43 var comment = gDb.getComment(iComment.commentId) ; |
|
44 this._q.add( |
|
45 function(){ |
|
46 |
|
47 unpaintCommentScope(comment) ; |
|
48 gIComments.close(comment.id) ; |
|
49 gIComments.remove(comment.id) ; |
|
50 if (comment.reply_to_id != null) |
|
51 gIComments.refresh(comment.reply_to_id) ; |
|
52 |
|
53 gDb.del(comment) ; |
|
54 |
|
55 if (gLayout.isInFrame()) { |
|
56 if (gDb.comments.length == 0 && gDb.allComments.length != 0) { |
|
57 parent.f_enqueueMsg(gettext("no filtered comments left")) ; |
|
58 parent.resetFilter() ; |
|
59 } |
|
60 else { |
|
61 // just counting here ... |
|
62 var filterRes = gDb.computeFilterResults() ; |
|
63 updateFilterResultsCount(filterRes['nbDiscussions'], filterRes['nbComments'], filterRes['nbReplies']) ; |
|
64 } |
|
65 } |
|
66 } |
|
67 ); |
|
68 |
|
69 this._animateTo(y) ; |
|
70 } |
|
71 this._q.add({fn:CY.bind(this.setPreventClickOff, this)}) ; |
|
72 this.resume() ; |
|
73 }, |
|
74 |
|
75 moderateCommentRet : function(args) { |
|
76 var successfull = args['successfull'] ; |
|
77 |
|
78 var iComment = (successfull) ? args['failure']['iComment'] : args['success']['iComment'] ; |
|
79 |
|
80 if (successfull) { |
|
81 var ret = args['returned'] ; |
|
82 var comment = ret['comment'] ; |
|
83 |
|
84 gDb.upd(comment) ; |
|
85 |
|
86 var shouldReset = gLayout.isInFrame() && !parent.f_isFrameFilterFieldsInit() ; |
|
87 if (shouldReset){ |
|
88 parent.resetFilter() ; |
|
89 this._showSingleComment(comment) ; |
|
90 } |
|
91 else |
|
92 iComment.changeModeration(comment) ; |
|
93 } |
|
94 |
|
95 this._q.add({fn:CY.bind(this.setPreventClickOff, this)}) ; |
|
96 this.resume() ; |
|
97 }, |
|
98 |
|
99 saveCommentRet : function(args) { |
|
100 var successfull = args['successfull'] ; |
|
101 if (successfull) { |
|
102 var formId = args['success']['formId'] ; |
|
103 var ret = args['returned'] ; |
|
104 |
|
105 removeFormErrMsg(formId) ; |
|
106 |
|
107 if ('errors' in ret) { // validation error |
|
108 var errors = ret['errors'] ; |
|
109 for (var eltName in errors) { |
|
110 addFormErrMsg(formId, eltName, errors[eltName]) ; |
|
111 } |
|
112 this._animateToTop() ; |
|
113 } |
|
114 else { |
|
115 var isReply = function() {return (gNewReply != null) && (formId == gNewReply['ids']['formId']) ;} ; |
|
116 var isNewComment = function() {return (gICommentForm != null) && (formId == gICommentForm['formId']) ;} ; |
|
117 var isEdit = function() {return (gEdit != null) && (formId == gEdit['ids']['formId']) ;} ; |
|
118 |
|
119 // doing this here for the a priori moderation case |
|
120 if (isNewComment()) |
|
121 this.hideICommentForm(cleanICommentForm()) ; |
|
122 else if (isEdit()) |
|
123 this._hideEditForm() ; |
|
124 else if (isReply()) |
|
125 this._hideNewReplyForm() ; |
|
126 |
|
127 if ("comment" in ret) { // won't be when add with a priori moderation |
|
128 var comment = ret['comment'] ; |
|
129 |
|
130 gDb.upd(comment) ; |
|
131 |
|
132 var shouldReset = gLayout.isInFrame() && !parent.f_isFrameFilterFieldsInit() ; |
|
133 if (shouldReset) |
|
134 parent.resetFilter() ; |
|
135 else { // ASSUMING filter is in init state ! (because when not // TODO $$$$$$$$$$$ this isn't true anymore .... when passing filter arguments in url !! |
|
136 // in frame for now data can't be filtered) |
|
137 if (comment.reply_to_id == null) { // not a reply |
|
138 unpaintCommentScope(comment) ; // for the edit case |
|
139 paintCommentScope(comment) ; |
|
140 } |
|
141 } |
|
142 |
|
143 // UPDATE FILTER DATA // TODO move ???? |
|
144 var filterData = ret['filterData'] ; |
|
145 if (gLayout.isInFrame()) { |
|
146 parent.f_updateFilterData(filterData) ; |
|
147 updateResetFilterResultsCount() ; |
|
148 } |
|
149 |
|
150 if (isReply()) { // add reply case |
|
151 if (!shouldReset) { |
|
152 this._insertReply(comment) ; |
|
153 } |
|
154 } |
|
155 else { // edit (reply or comment) or add (comment) case |
|
156 this._showSingleComment(comment) ; |
|
157 } |
|
158 } |
|
159 else |
|
160 this._animateToTop() ; |
|
161 } |
|
162 |
|
163 } |
|
164 else { // TODO ? ALL ret-FUNCTIONS ? |
|
165 this._q.add({id:"expl", fn:function () {CY.log('in example .........') ;}}) ; |
|
166 this._q.promote("expl") ; |
|
167 } |
|
168 |
|
169 this._q.add({fn:CY.bind(this.setPreventClickOff, this)}) ; |
|
170 this.resume() ; |
|
171 }, |
|
172 |
|
173 example : function () { |
|
174 CY.log('in example .........') ; |
|
175 }, |
|
176 |
|
177 moderateComment : function(iComment, state) { |
|
178 var comment = gDb.getComment(iComment['commentId']) ; |
|
179 this._q.add( |
|
180 {fn:CY.bind(this.setPreventClickOn, this)}, |
|
181 {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"))} |
|
182 ).run(); |
|
183 }, |
|
184 |
|
185 _saveComment : function(serverFun, formId) { |
|
186 this._q.add( |
|
187 {fn:CY.bind(this.setPreventClickOn, this)}, |
|
188 {autoContinue:false, fn:CY.bind(doExchange, null, serverFun, {}, formId, this.saveCommentRet, this, {'formId':formId}, gettext("could not save comment"))} |
|
189 ).run(); |
|
190 }, |
|
191 |
|
192 editComment : function() { |
|
193 this._saveComment("editComment", gEdit['ids']['formId']) ; |
|
194 }, |
|
195 |
|
196 saveComment : function(formId) { |
|
197 this._saveComment("addComment", formId) ; |
|
198 }, |
|
199 |
|
200 removeComment : function(iComment) { |
|
201 checkForOpenedDialog(iComment, function() { |
|
202 if (gLayout.isInFrame()) { |
|
203 parent.f_yesNoDialog(gettext("Are you sure you want to delete this comment?"), gettext("Warning"), function() { this.animateToTop() ;}, this, null, function() { |
|
204 var comment = gDb.getComment(iComment.commentId) ; |
|
205 this._q.add( |
|
206 {fn:CY.bind(this.setPreventClickOn, this)}, |
|
207 {autoContinue:false, fn:CY.bind(doExchange, null, "removeComment", {'comment_key':comment.key}, null, this.removeCommentRet, this, {'iComment':iComment}, gettext("could not remove comment"))} |
|
208 ).run(); |
|
209 }, this, null) ; |
|
210 |
|
211 } |
|
212 // else { |
|
213 // alert("TODO : can't yet delete comments when not embed in text_view_frame because can't 'dialog' confirmation") ; |
|
214 // } |
|
215 |
|
216 }, this, null) ; |
|
217 }, |
|
218 |
|
219 resume : function(commentDbIds, mouseXY) { |
|
220 this._q.run() ; |
|
221 }, |
|
222 |
|
223 resetAutoContinue : function(callbackId) { |
|
224 this._q.getCallback(callbackId).autoContinue = true; |
|
225 }, |
|
226 |
|
227 hideICommentForm : function(funObj) { |
|
228 // this._q.add({fn:function() {persistICommentFormValues();}}) ; |
|
229 this._q.add({autoContinue:false, fn:CY.bind(gICommentForm['animationHide'].run, gICommentForm['animationHide'])}) ; |
|
230 // this._q.add({fn:function() {cleanICommentForm();}}) ; |
|
231 if (funObj) |
|
232 this._q.add(funObj) ; |
|
233 }, |
|
234 |
|
235 /* ANIMATION DRIVEN INTERFACE CHANGES */ |
|
236 |
|
237 showCommentForm : function(iComment) { |
|
238 checkForOpenedDialog(null, function() { |
|
239 this._q.add({fn:CY.bind(this.setPreventClickOn, this)}); |
|
240 this._q.add({fn:function() { |
|
241 if (iComment == null) { |
|
242 var selection = getSelectionInfo() ; |
|
243 updateICommentFormSelection(selection) ; |
|
244 } |
|
245 showICommentForm(iComment); |
|
246 }}) ; |
|
247 this._q.add({autoContinue:false, fn:CY.bind(gICommentForm['animationShow'].run, gICommentForm['animationShow'])}, |
|
248 {fn:CY.bind(this.setPreventClickOff, this)} |
|
249 ).run(); |
|
250 }, this, null) ; |
|
251 }, |
|
252 |
|
253 showEditForm : function(iComment) { |
|
254 checkForOpenedDialog(null, function() { |
|
255 this._q.add({fn:CY.bind(this.setPreventClickOn, this)}); |
|
256 |
|
257 this._q.add({fn:function() { |
|
258 showEditForm(iComment) ; |
|
259 }}); |
|
260 this._animateToTop() ; |
|
261 |
|
262 this._q.add({fn:CY.bind(this.setPreventClickOff, this)}); |
|
263 this._q.run() ; |
|
264 }, this, null) ; |
|
265 }, |
|
266 |
|
267 showReplyForm : function(iComment) { |
|
268 checkForOpenedDialog(null, function() { |
|
269 this._q.add({fn:CY.bind(this.setPreventClickOn, this)}); |
|
270 |
|
271 this._q.add({fn:function() { |
|
272 instanciateNewReplyForm(iComment) ; |
|
273 }}); |
|
274 this._animateToTop() ; |
|
275 |
|
276 this._q.add({fn:CY.bind(this.setPreventClickOff, this)}); |
|
277 this._q.run() ; |
|
278 }, this, null) ; |
|
279 }, |
|
280 |
|
281 cancelICommentForm : function() { |
|
282 this._q.add({fn:CY.bind(this.setPreventClickOn, this)}); |
|
283 |
|
284 // this._q.add({fn:function() {cleanICommentForm();}}) ; |
|
285 this.hideICommentForm() ; |
|
286 |
|
287 this._q.add({fn:CY.bind(this.setPreventClickOff, this)}); |
|
288 this._q.run() ; |
|
289 }, |
|
290 cancelEdit : function() { |
|
291 this._q.add({fn:CY.bind(this.setPreventClickOn, this)}); |
|
292 |
|
293 this._q.add({fn:function() {cancelEditForm();}}) ; |
|
294 this._animateToTop() ; |
|
295 |
|
296 this._q.add({fn:CY.bind(this.setPreventClickOff, this)}); |
|
297 this._q.run() ; |
|
298 }, |
|
299 cancelReply : function() { |
|
300 this._q.add({fn:CY.bind(this.setPreventClickOn, this)}); |
|
301 |
|
302 this._q.add({fn:function() {cancelNewReplyForm();}}) ; |
|
303 this._animateToTop() ; |
|
304 |
|
305 this._q.add({fn:CY.bind(this.setPreventClickOff, this)}); |
|
306 this._q.run() ; |
|
307 }, |
|
308 changeScopeFormClick : function() { |
|
309 this._q.add({fn:CY.bind(this.setPreventClickOn, this)}); |
|
310 |
|
311 this._q.add({fn:function() {changeScopeFormClick();}}) ; |
|
312 this._animateToTop() ; |
|
313 |
|
314 this._q.add({fn:CY.bind(this.setPreventClickOff, this)}); |
|
315 this._q.run() ; |
|
316 }, |
|
317 // this is invoked during queue execution |
|
318 _hideNewReplyForm : function() { |
|
319 this._q.add({fn:function() { |
|
320 cleanNewReplyForm() ; |
|
321 cancelNewReplyForm() ;}}) ; |
|
322 }, |
|
323 // this is invoked during queue execution |
|
324 _hideEditForm : function() { |
|
325 this._q.add({fn:function() { |
|
326 cancelEditForm() ;}}) ; |
|
327 }, |
|
328 // this is invoked during queue execution |
|
329 _insertReply : function(comment) { |
|
330 this._q.add({fn:function() { |
|
331 var parentComment = gDb.getComment(comment.reply_to_id) ; |
|
332 var parentThread = gDb.getThreads([parentComment]) ; |
|
333 var previousComment = parentThread[parentThread.length - 2] ; // - 2 because now that comment has been added comment is parentThread[parentThread.length - 1] |
|
334 |
|
335 var iComment = gIComments.insertAfter(previousComment, comment) ; |
|
336 // iComment CAN'T BE NULL ! (TODO check that there is a |
|
337 // check server side that parent exists when adding a reply |
|
338 // !) |
|
339 |
|
340 var parentPosition = gIComments.getPosition(comment.reply_to_id) ; |
|
341 iComment.setPosition(parentPosition) ; |
|
342 |
|
343 // check if activation is necessary (will always be ?) |
|
344 var comment_path = gDb.getPath(comment) ; |
|
345 var topComment = comment_path[comment_path.length - 1] ; |
|
346 if (gIComments.isTopActive(topComment.id)) |
|
347 iComment.activate() ; |
|
348 |
|
349 iComment.show() ;}}) ; |
|
350 this._animateToTop() ; |
|
351 }, |
|
352 _showSingleComment : function(comment) { |
|
353 if (comment != null) { |
|
354 var path = gDb.getPath(comment) ; |
|
355 var topAncestorComment = path[path.length - 1] ; |
|
356 var topY = CY.get(".c-id-"+topAncestorComment.id).getY() ; |
|
357 this._showComments([topAncestorComment.id], topY, false) ; |
|
358 // optim when browsing comments with no reply |
|
359 if (topAncestorComment.replies.length > 0) |
|
360 this._animateTo(topY) ; |
|
361 } |
|
362 }, |
|
363 |
|
364 showSingleComment : function(comment) { |
|
365 this._q.add({fn:CY.bind(this.setPreventClickOn, this)}) ; |
|
366 this._showSingleComment(comment) ; |
|
367 this._q.add({fn:CY.bind(this.setPreventClickOff, this)}) ; |
|
368 this._q.run(); |
|
369 }, |
|
370 |
|
371 browse : function(order, whereto) { |
|
372 var comment = gIComments.browse(order, whereto) ; |
|
373 if (comment != null) |
|
374 this.showSingleComment(comment) ; |
|
375 }, |
|
376 |
|
377 _showComments : function(commentDbIds, topY, showingAll) { |
|
378 this._q.add( |
|
379 {fn:function() { |
|
380 gShowingAllComments = showingAll ; |
|
381 gIComments.hide() ; |
|
382 var cs = CY.Array.map(commentDbIds, function(id) { return gDb.getComment(id) ; }) ; |
|
383 var comments = gDb.getThreads(cs) ; |
|
384 gIComments.fetch(comments) ; |
|
385 |
|
386 if (commentDbIds.length > 0) { |
|
387 if (!showingAll) { |
|
388 gIComments.activate(commentDbIds[0]) ; |
|
389 var scopeStart = CY.get(".c-id-"+commentDbIds[0]) ; |
|
390 if (!scopeStart.inViewportRegion()) |
|
391 scopeStart.scrollIntoView(true) ; |
|
392 } |
|
393 else { |
|
394 CY.get('document').set('scrollTop', 0) ; |
|
395 } |
|
396 } |
|
397 |
|
398 gIComments.setPosition([gConf['iCommentLeftPadding'], topY]) ; |
|
399 |
|
400 gIComments.show() ; |
|
401 }}) ; |
|
402 }, |
|
403 |
|
404 _animateTo : function(topY) { |
|
405 this._q.add({fn:function() { |
|
406 gIComments.setAnimationToPositions(topY) ; |
|
407 }}, |
|
408 {id:"animationRun", autoContinue:false, fn:CY.bind(gIComments.runAnimations, gIComments)} |
|
409 ) ; |
|
410 }, |
|
411 |
|
412 _animateToTop : function() { |
|
413 var topPos = gIComments.getTopPosition() ; |
|
414 if (topPos != null) |
|
415 this._animateTo(topPos[1]) ; |
|
416 }, |
|
417 |
|
418 animateToTop : function() { |
|
419 this._q.add({fn:CY.bind(this.setPreventClickOn, this)}) ; |
|
420 this._animateToTop() ; |
|
421 this._q.add({fn:CY.bind(this.setPreventClickOff, this)}) ; |
|
422 this._q.run(); |
|
423 }, |
|
424 |
|
425 showAllComments : function() { |
|
426 checkForOpenedDialog(null, function() { |
|
427 gShowingAllComments = true ; |
|
428 var allTopComments = CY.Array.map(gDb.comments, function(c){return c.id;}) ; |
|
429 this.showComments(allTopComments, [0,0], true) ; |
|
430 }, this, null) ; |
|
431 }, |
|
432 |
|
433 showComments : function(commentDbIds, mouseXY, showingAll) { |
|
434 checkForOpenedDialog(null, function() { |
|
435 this._q.add({fn:CY.bind(this.setPreventClickOn, this)}) ; |
|
436 this._showComments(commentDbIds, mouseXY[1], showingAll) ; |
|
437 this._animateTo(mouseXY[1]) ; |
|
438 this._q.add({fn:CY.bind(this.setPreventClickOff, this)}) ; |
|
439 this._q.run(); |
|
440 }, this, null) ; |
|
441 }, |
|
442 |
|
443 openComment : function(iComment) { |
|
444 this._q.add({fn:CY.bind(this.setPreventClickOn, this)}) ; |
|
445 |
|
446 var y = gIComments.getTopPosition()[1] ; |
|
447 this._q.add({fn:function() { |
|
448 gIComments.open(iComment.commentId) ; |
|
449 gIComments.refresh(iComment.commentId) ; |
|
450 }}) ; |
|
451 this._animateTo(y) ; |
|
452 |
|
453 this._q.add({fn:CY.bind(this.setPreventClickOff, this)}) ; |
|
454 this._q.run(); |
|
455 }, |
|
456 |
|
457 closeComment : function(iComment) { |
|
458 checkForOpenedDialog(iComment, function() { |
|
459 this._q.add({fn:CY.bind(this.setPreventClickOn, this)}) ; |
|
460 |
|
461 var y = gIComments.getTopPosition()[1] ; |
|
462 this._q.add({fn:function() { |
|
463 var comment = gDb.getComment(iComment.commentId) ; |
|
464 gIComments.close(iComment.commentId) ; |
|
465 if (comment.reply_to_id != null) |
|
466 gIComments.refresh(comment.reply_to_id) ; |
|
467 }}) ; |
|
468 this._animateTo(y) ; |
|
469 |
|
470 this._q.add({fn:CY.bind(this.setPreventClickOff, this)}) ; |
|
471 this._q.run() ; |
|
472 }, this, null) ; |
|
473 }, |
|
474 |
|
475 activate : function(iComment) { |
|
476 gIComments.activate(iComment.commentId) ; |
|
477 } |
|
478 } |
|
479 |
|
480 readyForAction = function () { |
|
481 return !gSync._iPreventClick ; |
|
482 }; |