3
3
abstract class PhabricatorInlineCommentController
4
4
extends PhabricatorController {
5
5
6
+ private $ containerObject ;
7
+
6
8
abstract protected function createComment ();
7
9
abstract protected function newInlineCommentQuery ();
8
10
abstract protected function loadCommentForDone ($ id );
9
11
abstract protected function loadObjectOwnerPHID (
10
12
PhabricatorInlineComment $ inline );
11
- abstract protected function deleteComment (
12
- PhabricatorInlineComment $ inline );
13
- abstract protected function undeleteComment (
14
- PhabricatorInlineComment $ inline );
15
- abstract protected function saveComment (
16
- PhabricatorInlineComment $ inline );
13
+ abstract protected function newContainerObject ();
14
+
15
+ final protected function getContainerObject () {
16
+ if ($ this ->containerObject === null ) {
17
+ $ object = $ this ->newContainerObject ();
18
+ if (!$ object ) {
19
+ throw new Exception (
20
+ pht (
21
+ 'Failed to load container object for inline comment. ' ));
22
+ }
23
+ $ this ->containerObject = $ object ;
24
+ }
25
+
26
+ return $ this ->containerObject ;
27
+ }
17
28
18
29
protected function hideComments (array $ ids ) {
19
30
throw new PhutilMethodNotImplementedException ();
@@ -173,11 +184,13 @@ public function processRequest() {
173
184
$ inline = $ this ->loadCommentByIDForEdit ($ this ->getCommentID ());
174
185
175
186
if ($ is_delete ) {
176
- $ this -> deleteComment ( $ inline );
187
+ $ inline -> setIsDeleted ( 1 );
177
188
} else {
178
- $ this -> undeleteComment ( $ inline );
189
+ $ inline -> setIsDeleted ( 0 );
179
190
}
180
191
192
+ $ this ->saveComment ($ inline );
193
+
181
194
return $ this ->buildEmptyResponse ();
182
195
case 'edit ' :
183
196
$ inline = $ this ->loadCommentByIDForEdit ($ this ->getCommentID ());
@@ -190,33 +203,49 @@ public function processRequest() {
190
203
->setIsEditing (false );
191
204
192
205
$ this ->saveComment ($ inline );
193
- $ this ->purgeVersionedDrafts ($ inline );
194
206
195
207
return $ this ->buildRenderedCommentResponse (
196
208
$ inline ,
197
209
$ this ->getIsOnRight ());
198
210
} else {
199
- $ this ->deleteComment ($ inline );
200
- $ this ->purgeVersionedDrafts ($ inline );
211
+ $ inline ->setIsDeleted (1 );
212
+
213
+ $ this ->saveComment ($ inline );
201
214
202
215
return $ this ->buildEmptyResponse ();
203
216
}
204
217
} else {
205
- $ inline ->setIsEditing (true );
218
+ // NOTE: At time of writing, the "editing" state of inlines is
219
+ // preserved by simluating a click on "Edit" when the inline loads.
206
220
207
- if (strlen ($ text )) {
208
- $ inline ->setContent ($ text );
209
- }
221
+ // In this case, we don't want to "saveComment()", because it
222
+ // recalculates object drafts and purges versioned drafts.
223
+
224
+ // The recalculation is merely unnecessary (state doesn't change)
225
+ // but purging drafts means that loading a page and then closing it
226
+ // discards your drafts.
210
227
211
- $ this ->saveComment ($ inline );
228
+ // To avoid the purge, only invoke "saveComment()" if we actually
229
+ // have changes to apply.
230
+
231
+ $ is_dirty = false ;
232
+ if (!$ inline ->getIsEditing ()) {
233
+ $ inline ->setIsEditing (true );
234
+ $ is_dirty = true ;
235
+ }
212
236
213
237
if (strlen ($ text )) {
214
- $ this ->purgeVersionedDrafts ($ inline );
238
+ $ inline ->setContent ($ text );
239
+ $ is_dirty = true ;
240
+ } else {
241
+ PhabricatorInlineComment::loadAndAttachVersionedDrafts (
242
+ $ viewer ,
243
+ array ($ inline ));
215
244
}
216
245
217
- PhabricatorInlineComment:: loadAndAttachVersionedDrafts (
218
- $ viewer ,
219
- array ( $ inline ));
246
+ if ( $ is_dirty ) {
247
+ $ this -> saveComment ( $ inline );
248
+ }
220
249
}
221
250
222
251
$ edit_dialog = $ this ->buildEditDialog ($ inline )
@@ -240,12 +269,10 @@ public function processRequest() {
240
269
241
270
$ content = $ inline ->getContent ();
242
271
if (!strlen ($ content )) {
243
- $ this ->deleteComment ($ inline );
244
- } else {
245
- $ this ->saveComment ($ inline );
272
+ $ inline ->setIsDeleted (1 );
246
273
}
247
274
248
- $ this ->purgeVersionedDrafts ($ inline );
275
+ $ this ->saveComment ($ inline );
249
276
250
277
return $ this ->buildEmptyResponse ();
251
278
case 'draft ' :
@@ -262,6 +289,17 @@ public function processRequest() {
262
289
->setProperty ('inline.text ' , $ text )
263
290
->save ();
264
291
292
+ // We have to synchronize the draft engine after saving a versioned
293
+ // draft, because taking an inline comment from "no text, no draft"
294
+ // to "no text, text in a draft" marks the container object as having
295
+ // a draft.
296
+ $ draft_engine = $ this ->newDraftEngine ();
297
+ if ($ draft_engine ) {
298
+ $ draft_engine ->synchronize ();
299
+ } else {
300
+ phlog ('no draft engine ' );
301
+ }
302
+
265
303
return $ this ->buildEmptyResponse ();
266
304
case 'new ' :
267
305
case 'reply ' :
@@ -432,14 +470,6 @@ private function newInlineResponse(
432
470
->setContent ($ response );
433
471
}
434
472
435
- private function purgeVersionedDrafts (
436
- PhabricatorInlineComment $ inline ) {
437
- $ viewer = $ this ->getViewer ();
438
- PhabricatorVersionedDraft::purgeDrafts (
439
- $ inline ->getPHID (),
440
- $ viewer ->getPHID ());
441
- }
442
-
443
473
final protected function loadCommentByID ($ id ) {
444
474
$ query = $ this ->newInlineCommentQuery ()
445
475
->withIDs (array ($ id ));
@@ -494,4 +524,35 @@ private function loadCommentByQuery(
494
524
return $ inline ;
495
525
}
496
526
527
+ private function saveComment (PhabricatorInlineComment $ inline ) {
528
+ $ viewer = $ this ->getViewer ();
529
+ $ draft_engine = $ this ->newDraftEngine ();
530
+
531
+ $ inline ->openTransaction ();
532
+ $ inline ->save ();
533
+
534
+ PhabricatorVersionedDraft::purgeDrafts (
535
+ $ inline ->getPHID (),
536
+ $ viewer ->getPHID ());
537
+
538
+ if ($ draft_engine ) {
539
+ $ draft_engine ->synchronize ();
540
+ }
541
+
542
+ $ inline ->saveTransaction ();
543
+ }
544
+
545
+ private function newDraftEngine () {
546
+ $ viewer = $ this ->getViewer ();
547
+ $ object = $ this ->getContainerObject ();
548
+
549
+ if (!($ object instanceof PhabricatorDraftInterface)) {
550
+ return null ;
551
+ }
552
+
553
+ return $ object ->newDraftEngine ()
554
+ ->setObject ($ object )
555
+ ->setViewer ($ viewer );
556
+ }
557
+
497
558
}
0 commit comments