Index: trunk/extensions/LiquidThreads/i18n/Lqt.i18n.php |
— | — | @@ -250,6 +250,16 @@ |
251 | 251 | 'lqt-sign-not-necessary' => 'It is not necessary to sign your post with four tildes. |
252 | 252 | The signature is shown automatically.', |
253 | 253 | 'lqt-marked-as-read-placeholder' => 'The thread $1 was marked as read.', |
| 254 | + 'lqt-change-subject' => 'Change subject', |
| 255 | + 'lqt-save-subject' => 'Save', |
| 256 | + 'lqt-save-subject-failed' => 'The following error occurred while attempting to '. |
| 257 | +'change the subject of this thread: $1', |
| 258 | + 'lqt-ajax-invalid-subject' => 'The subject you specified was invalid, probably '. |
| 259 | +'because it was too long.', |
| 260 | + 'lqt-ajax-no-subject' => 'You must specify a subject.', |
| 261 | + 'lqt-save-subject-error-unknown' => 'An unknown error occurred when attempting '. |
| 262 | +'to set the subject of this thread. Please try to do this by clicking "edit" on the top post.', |
| 263 | + 'lqt-cancel-subject-edit' => 'Cancel', |
254 | 264 | |
255 | 265 | // Feeds |
256 | 266 | 'lqt-feed-title-all' => '{{SITENAME}} — New posts', |
Index: trunk/extensions/LiquidThreads/classes/View.php |
— | — | @@ -852,6 +852,12 @@ |
853 | 853 | 'lqt-sign-not-necessary', |
854 | 854 | 'lqt-marked-as-read-placeholder', |
855 | 855 | 'lqt-email-undo', |
| 856 | + 'lqt-change-subject', |
| 857 | + 'lqt-save-subject', |
| 858 | + 'lqt-ajax-no-subject', |
| 859 | + 'lqt-ajax-invalid-subject', |
| 860 | + 'lqt-save-subject-error-unknown', |
| 861 | + 'lqt-cancel-subject-edit', |
856 | 862 | ); |
857 | 863 | |
858 | 864 | $data = array(); |
— | — | @@ -1092,8 +1098,9 @@ |
1093 | 1099 | |
1094 | 1100 | $id = 'lqt-header-' . $thread->id(); |
1095 | 1101 | |
1096 | | - $html = $this->output->parseInline( $thread->subjectWithoutIncrement() ); |
| 1102 | + $html = $this->output->parseInline( $thread->subject() ); |
1097 | 1103 | $html = Xml::tags( 'span', array( 'class' => 'mw-headline' ), $html ); |
| 1104 | + $html .= Xml::hidden( 'raw-header', $thread->subject() ); |
1098 | 1105 | $html = Xml::tags( 'h' . $this->headerLevel, |
1099 | 1106 | array( 'class' => 'lqt_header', 'id' => $id ), |
1100 | 1107 | $html ) . $commands_html; |
Index: trunk/extensions/LiquidThreads/classes/ThreadRevision.php |
— | — | @@ -56,6 +56,10 @@ |
57 | 57 | $timestamp = wfTimestampNow(); |
58 | 58 | } |
59 | 59 | |
| 60 | + if ( is_null( $comment ) ) { |
| 61 | + $comment = ''; |
| 62 | + } |
| 63 | + |
60 | 64 | $rev = new ThreadRevision; |
61 | 65 | |
62 | 66 | $rev->mThreadId = $thread->topmostThread()->id(); |
Index: trunk/extensions/LiquidThreads/api/ApiThreadAction.php |
— | — | @@ -550,6 +550,8 @@ |
551 | 551 | return; |
552 | 552 | } |
553 | 553 | |
| 554 | + $talkpage = $thread->article(); |
| 555 | + |
554 | 556 | $subject = $params['subject']; |
555 | 557 | $title = null; |
556 | 558 | $subjectOk = Thread::validateSubject( $subject, $title, null, $talkpage ); |
Index: trunk/extensions/LiquidThreads/lqt.js |
— | — | @@ -333,7 +333,133 @@ |
334 | 334 | } |
335 | 335 | } ); |
336 | 336 | }, |
| 337 | + |
| 338 | + 'setupThreadMenu' : function( menu, id ) { |
| 339 | + if ( menu.find('.lqt-command-edit-subject').length ) { |
| 340 | + return; |
| 341 | + } |
337 | 342 | |
| 343 | + var editSubjectField = $j('<li/>'); |
| 344 | + var editSubjectLink = $j('<a href="#"/>'); |
| 345 | + editSubjectLink.text( wgLqtMessages['lqt-change-subject'] ); |
| 346 | + editSubjectField.append( editSubjectLink ); |
| 347 | + editSubjectField.click( liquidThreads.handleChangeSubject ); |
| 348 | + editSubjectField.data( 'thread-id', id ) |
| 349 | + |
| 350 | + editSubjectField.addClass( 'lqt-command-edit-subject' ); |
| 351 | + |
| 352 | + menu.append( editSubjectField ); |
| 353 | + }, |
| 354 | + |
| 355 | + 'handleChangeSubject' : function(e) { |
| 356 | + e.preventDefault(); |
| 357 | + |
| 358 | + // Grab the h2 |
| 359 | + var threadId = $j(this).data('thread-id'); |
| 360 | + var header = $j('#lqt-header-'+threadId); |
| 361 | + var headerText = header.find("input[name='raw-header']").val(); |
| 362 | + |
| 363 | + var textbox = $j('<input type="textbox" />').val(headerText); |
| 364 | + textbox.attr('id', 'lqt-subject-input-'+threadId); |
| 365 | + textbox.attr('size', '75'); |
| 366 | + textbox.val(headerText); |
| 367 | + |
| 368 | + var saveText = wgLqtMessages['lqt-save-subject']; |
| 369 | + var saveButton = $j('<input type="button" />'); |
| 370 | + saveButton.val( saveText ); |
| 371 | + saveButton.click( liquidThreads.handleSubjectSave ); |
| 372 | + |
| 373 | + var cancelButton = $j('<input type="button" />'); |
| 374 | + cancelButton.val( wgLqtMessages['lqt-cancel-subject-edit'] ); |
| 375 | + cancelButton.click( function(e) { |
| 376 | + var form = $j(this).closest('.mw-subject-editor'); |
| 377 | + var header = form.closest('.lqt_header'); |
| 378 | + header.contents().filter('.mw-headline').show(); |
| 379 | + form.remove(); |
| 380 | + |
| 381 | + } ); |
| 382 | + |
| 383 | + header.contents().filter('span.mw-headline').hide(); |
| 384 | + |
| 385 | + var subjectForm = $j('<span class="mw-subject-editor"/>'); |
| 386 | + subjectForm.append(textbox); |
| 387 | + subjectForm.append( ' ' ); |
| 388 | + subjectForm.append(saveButton); |
| 389 | + subjectForm.append( ' ' ); |
| 390 | + subjectForm.append( cancelButton ); |
| 391 | + subjectForm.data( 'thread-id', threadId ); |
| 392 | + |
| 393 | + header.append(subjectForm); |
| 394 | + |
| 395 | + }, |
| 396 | + |
| 397 | + 'handleSubjectSave' : function(e) { |
| 398 | + var button = $j(this); |
| 399 | + var subjectForm = button.closest('.mw-subject-editor'); |
| 400 | + var header = subjectForm.closest('.lqt_header'); |
| 401 | + var threadId = subjectForm.data('thread-id'); |
| 402 | + var textbox = $j('#lqt-subject-input-'+threadId); |
| 403 | + var newSubject = textbox.val().trim(); |
| 404 | + |
| 405 | + if (!newSubject) { |
| 406 | + alert( wgLqtMessages['lqt-ajax-no-subject'] ); |
| 407 | + return; |
| 408 | + } |
| 409 | + |
| 410 | + // Add a spinner |
| 411 | + var spinner = $j('<div class="mw-ajax-loader"/>'); |
| 412 | + header.append(spinner); |
| 413 | + subjectForm.hide(); |
| 414 | + |
| 415 | + var request = { |
| 416 | + 'action' : 'threadaction', |
| 417 | + 'threadaction' : 'setsubject', |
| 418 | + 'subject' : newSubject.trim(), |
| 419 | + 'thread' : threadId |
| 420 | + }; |
| 421 | + |
| 422 | + var errorHandler = function(reply) { |
| 423 | + try { |
| 424 | + code = reply.error.code; |
| 425 | + description = reply.error.info; |
| 426 | + |
| 427 | + if (code == 'invalid-subject') { |
| 428 | + alert( wgLqtMessages['lqt-ajax-invalid-subject'] ); |
| 429 | + } else { |
| 430 | + var msg = wgLqtMessages['lqt-save-subject-failed']; |
| 431 | + msg.replace( '$1', description ); |
| 432 | + } |
| 433 | + |
| 434 | + subjectForm.show(); |
| 435 | + spinner.remove(); |
| 436 | + } catch (err) { |
| 437 | + alert( wgLqtMessages['lqt-save-subject-error-unknown'] ); |
| 438 | + subjectForm.remove(); |
| 439 | + spinner.remove(); |
| 440 | + header.contents().filter('.mw-headline').show(); |
| 441 | + } |
| 442 | + } |
| 443 | + |
| 444 | + // Set new subject through API. |
| 445 | + liquidThreads.apiRequest( request, function(reply) { |
| 446 | + var result; |
| 447 | + |
| 448 | + try { |
| 449 | + result = reply.threadaction.thread.result; |
| 450 | + } catch (err) { |
| 451 | + result = 'error'; |
| 452 | + } |
| 453 | + |
| 454 | + if ( result == 'success' ) { |
| 455 | + spinner.remove(); |
| 456 | + var thread = $j('#lqt_thread_id_'+threadId); |
| 457 | + liquidThreads.doReloadThread( thread ); |
| 458 | + } else { |
| 459 | + errorHandler(reply); |
| 460 | + } |
| 461 | + } ); |
| 462 | + }, |
| 463 | + |
338 | 464 | 'handleDocumentClick' : function(e) { |
339 | 465 | // Collapse all menus |
340 | 466 | $j('.lqt-thread-toolbar-command-list').hide('fast'); |
— | — | @@ -483,6 +609,14 @@ |
484 | 610 | // Update menus |
485 | 611 | $j(threadContainer).each( liquidThreads.setupMenus ); |
486 | 612 | |
| 613 | + // Update thread-level menu, if appropriate |
| 614 | + if ( $j(threadWrapper).hasClass( 'lqt-thread-topmost' ) ) { |
| 615 | + var threadLevelCommandSelector = '#lqt-threadlevel-commands-'+threadId; |
| 616 | + |
| 617 | + var menu = $j(threadLevelCommandSelector); |
| 618 | + liquidThreads.setupThreadMenu( menu, threadId ); |
| 619 | + } |
| 620 | + |
487 | 621 | // Check for a "show replies" button |
488 | 622 | $j('a.lqt-show-replies').click( liquidThreads.showReplies ); |
489 | 623 | |
— | — | @@ -876,6 +1010,28 @@ |
877 | 1011 | } else { |
878 | 1012 | prevWarning.remove(); |
879 | 1013 | } |
| 1014 | + }, |
| 1015 | + |
| 1016 | + 'apiRequest' : function( request, callback ) { |
| 1017 | + // Set new subject through API. |
| 1018 | + liquidThreads.getToken( function(token) { |
| 1019 | + |
| 1020 | + if ( typeof request == 'function' ) { |
| 1021 | + request = request(token); |
| 1022 | + } else { |
| 1023 | + request.token = token; |
| 1024 | + } |
| 1025 | + |
| 1026 | + request.format = 'json'; |
| 1027 | + |
| 1028 | + var path = wgScriptPath+'/api'+wgScriptExtension; |
| 1029 | + $j.post( path, request, |
| 1030 | + function(data) { |
| 1031 | + if (callback) { |
| 1032 | + callback(data); |
| 1033 | + } |
| 1034 | + }, 'json' ); |
| 1035 | + } ); |
880 | 1036 | } |
881 | 1037 | } |
882 | 1038 | |