SamanthaNguyen has uploaded a new change for review. ( https://gerrit.wikimedia.org/r/380322 )
Change subject: [DNM] v4.4.0 - New form in OOUI with previewing + byte limit features ...................................................................... [DNM] v4.4.0 - New form in OOUI with previewing + byte limit features Not everything is fully implemented yet, but getting there. New features (outlined plan): - You can now preview your comment in wiki markup to help prevent mistakes before submitting. This can be done by writing your comment and then clicking on the "Preview" tab. - As a system administrator, you can decide whether or not to have an enforced byte limit turned on or off. By default, it is turned off. The variables include: - $wgCommentsEnableByteLimit - $wgCommentsByteLimitNumber TODO: - Handle buttons properly - Handle permissions properly - Make sure tabs show up - Use core jquery.byteLimit module for enforcing byte limit Based on original demo/experiment in: - https://samanthanguyen.github.io/mediawiki-demos/comments/demo.html Bug: T156055 Change-Id: I977089eedad5be5f944f8ffeb4ad757b7fda4517 --- M .jshintrc M extension.json M i18n/en.json M i18n/qqq.json M includes/CommentsPage.class.php A includes/interfaces/FormInterface.php M includes/parser/DisplayComments.class.php M resources/css/Comments.css A resources/css/ext.comments.form.ooui.styles.css A resources/js/ext.comments.form.ooui.js 10 files changed, 286 insertions(+), 63 deletions(-) git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/Comments refs/changes/22/380322/1 diff --git a/.jshintrc b/.jshintrc index 04c3a97..687fe80 100644 --- a/.jshintrc +++ b/.jshintrc @@ -18,6 +18,7 @@ "jquery": true, "globals": { - "mediaWiki": false + "mediaWiki": false, + "OO": false } } diff --git a/extension.json b/extension.json index 143c8dc..719f71a 100644 --- a/extension.json +++ b/extension.json @@ -1,6 +1,6 @@ { "name": "Comments", - "version": "4.3.2", + "version": "4.4.0", "author": [ "David Pean", "Misza", @@ -74,7 +74,8 @@ "CommentLatestIdAPI": "includes/api/CommentLatestID.api.php", "CommentListAPI": "includes/api/CommentList.api.php", "CommentSubmitAPI": "includes/api/CommentSubmit.api.php", - "CommentVoteAPI": "includes/api/CommentVote.api.php" + "CommentVoteAPI": "includes/api/CommentVote.api.php", + "FormInterface": "includes/interfaces/FormInterface.php" }, "ResourceModules": { "ext.comments.css": { @@ -95,6 +96,25 @@ "comments-block-warning-user", "comments-delete-warning" ] + }, + "ext.comments.form.ooui.styles": { + "styles": "resources/css/ext.comments.forms.ooui.styles.css", + "position": "top" + }, + "ext.comments.form.ooui": { + "scripts": "resources/js/ext.comments.form.ooui.js", + "dependencies": [ + "oojs-ui-core", + "oojs-ui-widgets", + "oojs-ui.styles.icons-alerts" + ], + "messages": [ + "comments-preview-failed", + "comments-tab-write", + "comments-tab-preview", + "comments-post", + "comments-cancel-reply" + ] } }, "ResourceFileModulePaths": { @@ -111,7 +131,9 @@ "config": { "CommentsDefaultAvatar": "http://www.shoutwiki.com/w/extensions/SocialProfile/avatars/default_ml.gif", "CommentsSortDescending": false, - "CommentsInRecentChanges": false + "CommentsInRecentChanges": false, + "CommentsEnableByteLimit": false, + "CommentsByteLimitNumber": "" }, "manifest_version": 1 } diff --git a/i18n/en.json b/i18n/en.json index 78e4940..c97108b 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -67,6 +67,10 @@ "comments-ignore-title": "Comment ignore list", "commentignorelist": "Comment ignore list", "comments-no-comments-of-day": "There are no comments of the day.", + "comments-textarea-placeholder": "Add a comment", + "comments-tab-write": "Write", + "comments-tab-preview": "Preview", + "comments-preview-failed": "Previewing failed. Please try again.", "log-name-comments": "Comments log", "log-description-comments": "This is a log of comments.", "logentry-comments-add": "$1 posted a new comment on $3", diff --git a/i18n/qqq.json b/i18n/qqq.json index c6e6340..6c81e69 100644 --- a/i18n/qqq.json +++ b/i18n/qqq.json @@ -75,6 +75,10 @@ "comments-ignore-title": "Title of Special:CommentIgnoreList, as shown on the said page.", "commentignorelist": "{{doc-special|CommentIgnoreList}}\nThe comment ignore list contains a list of users whose comments you are ignoring; an ignored comment won't show up by default and you have to click on a special link to view it", "comments-no-comments-of-day": "Shown as the output of the <code><nowiki><commentsoftheday /></nowiki></code> parser hook if there are no comments of the day.", + "comments-textarea-placeholder": "Placeholder shown in the comment textarea when the end-user hasn't written anything yet.", + "comments-tab-write": "A verb as a title for a tab panel that lets the end-user write their own comment.", + "comments-tab-preview": "A verb as a title for a tab panel that lets the end-user preview their comment parsed as wiki markup.", + "comments-preview-failed": "Error given when previewing the wikitext of the comment fails.", "log-name-comments": "Shown on the dropdown on [[Special:Log]].", "log-description-comments": "Explanation of the comments log, shown on [[Special:Log/comments]].", "logentry-comments-add": "Parameters:\n* $1 - contains the user name + talk/block/contribs links, as is the standard with log entries nowadays\n* $2 - (Optional) username, for <nowiki>{{GENDER}}</nowiki> support\n* $3 - a wikilink to the page where the comment was posted; it contains a fragment that directly points to the new comment in question, i.e. [[Talk:Main Page#comment-10]] (the number is the internal comment identifier)", diff --git a/includes/CommentsPage.class.php b/includes/CommentsPage.class.php index b6050cf..c843c4a 100644 --- a/includes/CommentsPage.class.php +++ b/includes/CommentsPage.class.php @@ -547,49 +547,15 @@ * @return string HTML output */ function displayForm() { - $output = '<form action="" method="post" name="commentForm">' . "\n"; + $form = new FormInterface; + + MediaWiki\suppressWarnings(); + $form->setRef( 'commentPage', $this ); + $form->setRef( 'user', $this->getUser() ); + MediaWiki\restoreWarnings(); - if ( $this->allow ) { - $pos = strpos( - strtoupper( addslashes( $this->allow ) ), - strtoupper( addslashes( $this->getUser()->getName() ) ) - ); - } - - // 'comment' user right is required to add new comments - if ( !$this->getUser()->isAllowed( 'comment' ) ) { - $output .= wfMessage( 'comments-not-allowed' )->parse(); - } else { - // Blocked users can't add new comments under any conditions... - // and maybe there's a list of users who should be allowed to post - // comments - if ( $this->getUser()->isBlocked() == false && ( $this->allow == '' || $pos !== false ) ) { - $output .= '<div class="c-form-title">' . wfMessage( 'comments-submit' )->plain() . '</div>' . "\n"; - $output .= '<div id="replyto" class="c-form-reply-to"></div>' . "\n"; - // Show a message to anons, prompting them to register or log in - if ( !$this->getUser()->isLoggedIn() ) { - $login_title = SpecialPage::getTitleFor( 'Userlogin' ); - $register_title = SpecialPage::getTitleFor( 'Userlogin', 'signup' ); - $output .= '<div class="c-form-message">' . wfMessage( - 'comments-anon-message', - htmlspecialchars( $register_title->getFullURL() ), - htmlspecialchars( $login_title->getFullURL() ) - )->text() . '</div>' . "\n"; - } - - $output .= '<textarea name="commentText" id="comment" rows="5" cols="64"></textarea>' . "\n"; - $output .= '<div class="c-form-button"><input type="button" value="' . - wfMessage( 'comments-post' )->plain() . '" class="site-button" /></div>' . "\n"; - } - $output .= '<input type="hidden" name="action" value="purge" />' . "\n"; - $output .= '<input type="hidden" name="pageId" value="' . $this->id . '" />' . "\n"; - $output .= '<input type="hidden" name="commentid" />' . "\n"; - $output .= '<input type="hidden" name="lastCommentId" value="' . $this->getLatestCommentID() . '" />' . "\n"; - $output .= '<input type="hidden" name="commentParentId" />' . "\n"; - $output .= '<input type="hidden" name="' . $this->pageQuery . '" value="' . $this->getCurrentPagerPage() . '" />' . "\n"; - $output .= Html::hidden( 'token', $this->getUser()->getEditToken() ); - } - $output .= '</form>' . "\n"; + $output = $form->getHTML(); + return $output; } diff --git a/includes/interfaces/FormInterface.php b/includes/interfaces/FormInterface.php new file mode 100644 index 0000000..12bee54 --- /dev/null +++ b/includes/interfaces/FormInterface.php @@ -0,0 +1,126 @@ +<?php + +class FormInterface extends QuickTemplate { + + public function getPermissions() { + $user = $this->data['user']; + if ( $this->data['commentPage']->allow ) { + $pos = strpos( + strtoupper( addslashes( $this->data['commentPage']->allow ) ), + strtoupper( addslashes( $user->getName() ) ) + ); + } + + // is the user allowed to comment? + if ( !$user->isAllowed( 'comment' ) ) { + // nope, show a message that they can't + echo wfMessage( 'comments-not-allowed' )->parse(); + return false; + } + + // is the user blocked? + if ( + $user->isBlocked() === false && ( + $this->data['commentPage']->allow === '' + || $pos === false ) + ) { + //echo some custom message for blocking + return false; + } + + // is the user not logged in? + if ( !$this->getUser()->isLoggedIn() ) { + $title['login'] = SpecialPage::getTitleFor( 'Userlogin' ); + $title['register'] = SpecialPage::getTitleFor( 'Userlogin', 'signup' ); + echo wfMessage( + 'comments-anon-message', + htmlspecialchars( $title['login']->getFullURL() ), + htmlspecialchars( $title['register']->getFullURL() ) + )->text(); + + return false; + } + } + + public function getAvatar() { + if ( class_exists( 'wAvatar' ) ) { + $avatar = new wAvatar( $user->getId(), 'ml' ); + $avatarUrl = $avatar->getAvatarURL( [ 'class' => 'avatar comments-form-avatar' ] ); + } else { + $avatarUrl = ''; + } + + return $avatarUrl; + } + + /** + * the OOUI\HiddenInputWidget isn't available + * in the oojs-ui package that comes with MediaWiki 1.29, + * but available with 1.30.0. For now, let's create + * our own OOUI hidden input widget to handle this, + * and keep everything OOUI-ified. + * + * @todo: Replace when 1.30.0 becomes the stable version + * + * @param $name + * @param $value + * @return $hidden + */ + public function getHidden( $name, $value ) { + $hidden = new OOUI\Tag( 'input' ); + $hidden->setAttributes( [ + 'type' => 'hidden', + 'id' => '', + 'name' => $name, + 'value' => $value + ] ); + + return $hidden; + } + + public function getForm() { + self::getPermissions(); + + $user = $this->data['user']; + + /** + * @todo: No PHP version of a OOUI\MultilineTextInputWidget yet, + * so use OOUI\TextInputWidget and 'multiline' => true for now + * + * @see: https://phabricator.wikimedia.org/T166686 + */ + $textarea = new OOUI\TextInputWidget( [ + 'infusable' => true, + 'multiline' => true, + 'placeholder' => wfMessage( 'comments-textarea-placeholder' ), + 'rows' => 8, + 'id' => 'CommentsTextareaWidget', + 'name' => 'commentText' + ] ); + + $form = new OOUI\FormLayout( [ + 'infusable' => true, + 'method' => 'post', + 'action' => '', + 'id' => 'CommentsFormLayout', + 'name' => 'commentForm', + 'items' => [ + $textarea, + // hidden input data + self::getHidden( 'action', 'purge' ), + self::getHidden( 'pageId', $this->data['commentPage']->id ), + self::getHidden( 'commentid', '' ), + self::getHidden( 'lastCommentId', $this->data['commentPage']->getLatestCommentID() ), + self::getHidden( 'commentParentId', '' ), + self::getHidden( $this->data['commentPage']->pageQuery, $this->data['commentPage']->getCurrentPagerPage() ), + self::getHidden( 'token', $user->getEditToken() ) + ] + ] ); + + return $form; + } + + public function execute() { + echo self::getForm(); + } +} \ No newline at end of file diff --git a/includes/parser/DisplayComments.class.php b/includes/parser/DisplayComments.class.php index 110188f..08b34e5 100644 --- a/includes/parser/DisplayComments.class.php +++ b/includes/parser/DisplayComments.class.php @@ -14,6 +14,7 @@ public static function getParserHandler( $input, $args, $parser ) { global $wgOut, $wgCommentsSortDescending; + $parser->enableOOUI(); $parser->disableCache(); // If an unclosed <comments> tag is added to a page, the extension will // go to an infinite loop...this protects against that condition. @@ -25,8 +26,8 @@ } // Add required CSS & JS via ResourceLoader - $wgOut->addModuleStyles( 'ext.comments.css' ); - $wgOut->addModules( 'ext.comments.js' ); + $wgOut->addModuleStyles( [ 'ext.comments.css', 'ext.comments.form.ooui.styles' ] ); + $wgOut->addModules( [ 'ext.comments.js', 'ext.comments.form.ooui' ] ); $wgOut->addJsConfigVars( array( 'wgCommentsSortDescending' => $wgCommentsSortDescending ) ); // Parse arguments diff --git a/resources/css/Comments.css b/resources/css/Comments.css index 93aa0f1..ca9e951 100644 --- a/resources/css/Comments.css +++ b/resources/css/Comments.css @@ -113,27 +113,12 @@ margin: -5px 0px 0px 2px } -.c-form-title { - color: #333; - font-weight: bold; - font-size: 17px; - margin: 0px 0px 5px 0px; -} - .c-form-message { font-size: 11px; width: 400px; line-height: 13px; color: #666; padding: 5px 0px 10px 0px; -} - -textarea#comment { - width: 530px; -} - -.c-form-button { - padding: 10px 0px 0px; } .c-order { diff --git a/resources/css/ext.comments.form.ooui.styles.css b/resources/css/ext.comments.form.ooui.styles.css new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/resources/css/ext.comments.form.ooui.styles.css diff --git a/resources/js/ext.comments.form.ooui.js b/resources/js/ext.comments.form.ooui.js new file mode 100644 index 0000000..c77d9b7 --- /dev/null +++ b/resources/js/ext.comments.form.ooui.js @@ -0,0 +1,114 @@ +/** + * Handles all functions related to the comment + * form, such as previewing and the tabs + * + * @file + */ +( function ( $, mw ) { + +var CommentsForm = { + + // infused OOUI widgets + layouts + form: oo.ui.infuse( 'CommentsFormLayout' ), + textarea: oo.ui.infuse( 'CommentsTextareaWidget' ), + avatar: oo.ui.infuse( 'CommentsAvatarWidget' ), + + // other elements + container: $( '.comments-body' ), + replyto: $( '#replyto' ), + + // configuration + isByteLimitEnabled: mw.config.get( 'wgCommentsEnableByteLimit' ), + getByteLimitNumber: mw.config.get( 'wgCommentsByteLimitNumber' ), + + /** + * Preview the contents of the <textarea> (more accurately the + * wikitext given to this function) and show the parsed HTML + * output in the given element. + * + * @param text {string} Wikitext to be sent to the API for parsing + * @param targetElement {string} ID of the element where + * the preview text should be inserted + */ + preview: function ( text, targetElement ) { + ( new mw.Api() ).get( { + action: 'parse', + text: text, + contentmodel: 'wikitext', + disablelimitreport: true // don't need the NewPP report stuff + } ).done( function ( data ) { + $( '#' + targetElement ).html( data.parse.text['*'] ); + } ).fail( function () { + $( '#' + targetElement ).text( mw.msg( 'comments-preview-failed' ) ); + } ); + }, + + /** + * build the buttons that let the user + * either submit or cancel their comment. + */ + buildButtons: function () { + var buttons = { + submit: new OO.ui.ButtonInputWidget( { + label: mw.msg( 'comments-post' ), + icon: 'speechBubbleAdd', + type: 'submit', + flags: [ 'primary', 'progressive' ] + } ), + cancel: new OO.ui.ButtonInputWidget( { + label: mw.msg( 'comments-cancel-reply' ), + frameless: true, + flags: [ 'destructive' ] + } ) + }; + + // decide what buttons to show + if ( CommentsForm.replyto.text() !== '' ) { + var group = new OO.ui.ButtonGroupWidget( { + items: [ + buttons.submit, + buttons.cancel + ] + } ); + return group; + } else { + return buttons.submit; + } + }, + + /** + * build the write and preview tab needed + * for the comment form + */ + buildTabs: function () { + var tabs = { + write: new OO.ui.TabPanelLayout( 'write', { + label: mw.msg( 'comments-tab-write' ), + } ), + preview: new OO.ui.TabPanelLayout( 'preview', { + label: mw.msg( 'comments-tab-preview' ) + } ) + }; + + tabs.write.$element.append( + CommentsForm.form.$element + ); + + tabs.preview.$element.append( + CommentsForm.preview( + textarea.val(), + $( this ).attr( 'data-linked-element' ) + ) + ); + + var index = new OO.ui.IndexLayout(); + index.addTabPanels( [ formTabs.write, tabs.preview ] ); + CommentsForm.container.html( index.$element ); + }, + + enforceByteLimit: function () { + // work in progress + } +} + +} ); \ No newline at end of file -- To view, visit https://gerrit.wikimedia.org/r/380322 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I977089eedad5be5f944f8ffeb4ad757b7fda4517 Gerrit-PatchSet: 1 Gerrit-Project: mediawiki/extensions/Comments Gerrit-Branch: master Gerrit-Owner: SamanthaNguyen <samanthanguyen1...@gmail.com> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits