http://www.mediawiki.org/wiki/Special:Code/MediaWiki/87294

Revision: 87294
Author:   janpaul123
Date:     2011-05-02 20:34:52 +0000 (Mon, 02 May 2011)
Log Message:
-----------
Added first very experimental -- but working! -- version of the WikiLove 
extension.

Modified Paths:
--------------
    trunk/extensions/WikiLove/WikiLove.i18n.php
    trunk/extensions/WikiLove/WikiLove.php

Added Paths:
-----------
    trunk/extensions/WikiLove/WikiLove.api.php
    trunk/extensions/WikiLove/WikiLove.hooks.php
    trunk/extensions/WikiLove/images/heart-hover.png
    trunk/extensions/WikiLove/images/heart-icons.png
    trunk/extensions/WikiLove/images/spinner.gif
    trunk/extensions/WikiLove/images/tab-break.png
    trunk/extensions/WikiLove/jquery.elastic.js
    trunk/extensions/WikiLove/patches/
    trunk/extensions/WikiLove/patches/WikiLoveLog.sql
    trunk/extensions/WikiLove/wikiLove.css
    trunk/extensions/WikiLove/wikiLove.js

Removed Paths:
-------------
    trunk/extensions/WikiLove/WikiLove.sql

Added: trunk/extensions/WikiLove/WikiLove.api.php
===================================================================
--- trunk/extensions/WikiLove/WikiLove.api.php                          (rev 0)
+++ trunk/extensions/WikiLove/WikiLove.api.php  2011-05-02 20:34:52 UTC (rev 
87294)
@@ -0,0 +1,126 @@
+<?php
+class WikiLoveApi extends ApiBase {
+       public function execute() {
+               global $wgRequest;
+               
+               $params = $this->extractRequestParams();
+               
+               $title = Title::newFromText( $params['title'] );
+               if ( is_null( $title ) ) {
+                       // error
+               }
+               
+               $talk = WikiLoveHooks::getUserTalkPage( $title );
+               if ( is_null( $talk ) ) {
+                       // error
+               }
+               
+               if ( stripos( $params['text'], $params['template'] ) === false 
) {
+                       // error
+               }
+               
+               $api = new ApiMain( new FauxRequest( array(
+                       'action' => 'edit',
+                       'title'  => $talk->getFullText(),
+                       'section' => 'new',
+                       'text' => $params['text'],
+                       'token'  => $params['token'],
+                       'summary' => $params['subject'],
+                       'notminor' => true,
+               ), false, array( 'wsEditToken' => $wgRequest->getSessionData( 
'wsEditToken' ) ) ), true );
+               $api->execute();
+               
+               $result = $api->getResult();
+               $data = $result->getData();
+               
+               $talk->setFragment( '#' . $params['subject'] );
+               $this->getResult()->addValue( 'redirect', 'pageName', 
$talk->getPrefixedDBkey() );
+               $this->getResult()->addValue( 'redirect', 'fragment', 
$talk->getFragmentForURL() );
+               
+               $this->saveInDb( $talk, $params['subject'], $params['text'], 
$params['type'], $params['template'] );
+       }
+       
+       private function saveInDb( $talk, $subject, $text, $type, $template ) {
+               global $wgUser, $wgSitename;
+               $dbw = wfGetDB( DB_MASTER );
+               $values = array(
+                       'wl_timestamp' => $dbw->timestamp(),
+                       'wl_sender_id' => $wgUser->getId(),
+                       'wl_receiver_id' => User::newFromName( 
$talk->getSubjectPage()->getBaseText() )->getId(),
+                       'wl_wiki' => $wgSitename,
+                       'wl_type' => $type,
+                       'wl_template' => $template,
+                       'wl_subject' => $subject,
+                       'wl_message' => $text,
+                       'wl_email' => 0,
+               );
+               $dbw->insert( 'wikilove_log', $values, __METHOD__ );
+       }
+
+       public function getAllowedParams() {
+               return array(
+                       'title' => array(
+                               ApiBase::PARAM_TYPE => 'string',
+                               ApiBase::PARAM_REQUIRED => true,
+                       ),
+                       'text' => array(
+                               ApiBase::PARAM_TYPE => 'string',
+                               ApiBase::PARAM_REQUIRED => true,
+                       ),
+                       'token' => array(
+                               ApiBase::PARAM_TYPE => 'string',
+                               ApiBase::PARAM_REQUIRED => true,
+                       ),
+                       'subject' => array(
+                               ApiBase::PARAM_TYPE => 'string',
+                               ApiBase::PARAM_REQUIRED => true,
+                       ),
+                       'template' => array(
+                               ApiBase::PARAM_TYPE => 'string',
+                       ),
+                       'type' => array(
+                               ApiBase::PARAM_TYPE => 'string',
+                       ),
+               );
+       }
+
+       public function getParamDescription() {
+               return array(
+                       'title' => 'Title of the user or user talk page to send 
WikiLove to',
+                       'text' => 'Wikitext to add in the new section',
+                       'token' => 'Edit token. You can get one of these 
through prop=info',
+                       'subject' => 'Subject header of the new section',
+                       'template' => 'Template used in the wikitext (for 
statistics)',
+                       'type' => 'Type of WikiLove (for statistics)',
+               );
+       }
+
+       public function getDescription() {
+               return array(
+                       'Give WikiLove to another user.',
+                       "WikiLove is a positive message posted to a user's talk 
page through a",
+                       'convenient interface with preset images and templates. 
For statistical',
+                       'purposes, the type and template (among the other data) 
are logged.',
+               );
+       }
+
+       /*
+       public function getPossibleErrors() {
+               return array_merge( parent::getPossibleErrors(), array(
+                       array( 'code' => 'permissiondenied', 'info' => 'You 
don\'t have permission to view code diffs' ),
+                       array( 'code' => 'invalidrepo', 'info' => "Invalid repo 
``repo''" ),
+                       array( 'code' => 'nosuchrev', 'info' => 'There is no 
revision with ID \'rev\'' ),
+               ) );
+       }
+       */
+
+       public function getExamples() {
+               return array(
+                       
'api.php?action=wikiLove&title=User:Dummy&text=Love&subject=Hi&token=%2B\\',
+               );
+       }
+
+       public function getVersion() {
+               return __CLASS__ . ': $Id$';
+       }
+}


Property changes on: trunk/extensions/WikiLove/WikiLove.api.php
___________________________________________________________________
Added: svn:keywords
   + Id
Added: svn:eol-style
   + native

Added: trunk/extensions/WikiLove/WikiLove.hooks.php
===================================================================
--- trunk/extensions/WikiLove/WikiLove.hooks.php                                
(rev 0)
+++ trunk/extensions/WikiLove/WikiLove.hooks.php        2011-05-02 20:34:52 UTC 
(rev 87294)
@@ -0,0 +1,126 @@
+<?php
+/**
+ * Hooks for WikiLove extension
+ * 
+ * @file
+ * @ingroup Extensions
+ */
+
+class WikiLoveHooks {
+       /**
+        * LoadExtensionSchemaUpdates hook
+        */
+       public static function loadExtensionSchemaUpdates( $updater = null ) {
+               if ( $updater === null ) {
+                       global $wgExtNewTables;
+                       $wgExtNewTables[] = array( 'wikilove_log', dirname( 
__FILE__ ) . '/patches/WikiLoveLog.sql' );
+               } else {
+                       $updater->addExtensionUpdate( array( 'addTable', 
'wikilove_log',
+                               dirname( __FILE__ ) . 
'/patches/WikiLoveLog.sql', true ) );
+               }
+               return true;
+       }
+       
+       /**
+        * Add the preference in the user preferences with the GetPreferences 
hook.
+        * @param $user
+        * @param $preferences
+        */
+       public static function getPreferences( $user, &$preferences ) {
+               global $wgWikiLoveGlobal;
+               if ( !$wgWikiLoveGlobal ) {
+                       $preferences['wikilove-enabled'] = array(
+                               'type' => 'check',
+                               'section' => 'editing/labs',
+                               'label-message' => 'wikilove-enable-preference',
+                       );
+               }
+               return true;
+       }
+       
+       /**
+        * Adds the required module and edit token JS if we are on a user 
(talk) page.
+        */
+       public static function beforePageDisplay( $out, $skin ) {
+               global $wgWikiLoveGlobal, $wgUser;
+               if ( !$wgWikiLoveGlobal && !$wgUser->getOption( 
'wikilove-enabled' ) ) return true;
+               
+               $title = self::getUserTalkPage( $skin->getTitle() );
+               if ( !is_null( $title ) ) {
+                       $out->addModules( 'ext.wikiLove' );
+                       $out->addInlineScript(
+                       'jQuery( document ).ready( function() {
+                               jQuery.wikiLove.editToken = ' . 
FormatJson::encode( $wgUser->edittoken() ) . ';
+                       } );'
+               );
+               }
+               return true;
+       }
+       
+       /**
+        * Adds a tab the old way (before MW 1.18)
+        */
+       public static function skinTemplateTabs( $skin, &$contentActions ) {
+               self::skinConfigViewsLinks( $skin, $contentActions );
+               return true;
+       }
+       
+       /**
+        * Adds a tab or an icon the new way (MW >1.18)
+        */
+       public static function skinTemplateNavigation( &$skin, &$links ) {
+               if ( self::showIcon( $skin ) ) {
+                       self::skinConfigViewsLinks( $skin, $links['views']);
+               }
+               else {
+                       self::skinConfigViewsLinks( $skin, $links['actions']);
+               }
+               return true;
+       }
+       
+       /**
+        * Configure views links.
+        * Helper function for SkinTemplateTabs and SkinTemplateNavigation hooks
+        * to configure views links.
+        */
+       private static function skinConfigViewsLinks( $skin, &$views ) {
+               global $wgWikiLoveGlobal, $wgUser;
+               if ( !$wgWikiLoveGlobal && !$wgUser->getOption( 
'wikilove-enabled' ) ) return true;
+               
+               if ( !is_null( self::getUserTalkPage( $skin->getTitle() ) ) ) {
+                       $views['wikilove'] = array(
+                               'text' => wfMsg( 'wikilove-tab-text' ),
+                               'href' => '#',
+                       );
+                       if ( self::showIcon( $skin ) ) {
+                               $views['wikilove']['class'] = 'icon';
+                               $views['wikilove']['primary'] = true;
+                       }
+               }
+       }
+       
+       /**
+        * Only show an icon when the global preference is enabled and the 
current skin is Vector.
+        */
+       private static function showIcon( $skin ) {
+               global $wgWikiLoveTabIcon;
+               return $wgWikiLoveTabIcon && $skin->getSkinName() == 'vector';
+       }
+       
+       /**
+        * Find the editable talk page of the user we're looking at, or null
+        * if such page does not exist.
+        */
+       public static function getUserTalkPage( $title ) {
+               global $wgUser;
+               if ( !$wgUser->isLoggedIn() ) return null;
+               
+               $ns = $title->getNamespace();
+               if ( $ns == NS_USER_TALK && $title->quickUserCan( 'edit' ) ) 
return $title;
+               elseif ( $ns == NS_USER ) {
+                       $talk = $title->getTalkPage();
+                       if ( $talk->quickUserCan( 'edit' ) ) return $talk;
+               }
+               return null;
+       }
+}
\ No newline at end of file


Property changes on: trunk/extensions/WikiLove/WikiLove.hooks.php
___________________________________________________________________
Added: svn:eol-style
   + native

Modified: trunk/extensions/WikiLove/WikiLove.i18n.php
===================================================================
--- trunk/extensions/WikiLove/WikiLove.i18n.php 2011-05-02 20:30:38 UTC (rev 
87293)
+++ trunk/extensions/WikiLove/WikiLove.i18n.php 2011-05-02 20:34:52 UTC (rev 
87294)
@@ -9,10 +9,22 @@
 $messages = array();
 
 /** English
- * @author Ryan Kaldari
+ * @author Ryan Kaldari, Jan Paul Posma
  */
 $messages['en'] = array(
        'wikilove-desc' => 'Adds an interface for facilitating positive user 
feedback to user talk pages',
        'wikilove' => 'WikiLove',
+       'wikilove-enable-preference' => 'Enable showing appreciation for other 
users with the WikiLove tab (experimental)',
+       'wikilove-tab-text' => 'Show appreciation',
+       'tooltip-ca-wikilove' => 'Post a message for this user showing your 
appreciation',
+       'wikilove-dialog-title' => 'WikiLove',
+       'wikilove-select-type' => 'Select Type',
+       'wikilove-add-details' => 'Add Details',
+       'wikilove-title' => 'Title:',
+       'wikilove-enter-message' => 'Enter a message:',
+       'wikilove-omit-sig' => '(without a signature)',
+       'wikilove-button-preview' => 'Preview',
+       'wikilove-preview' => 'Preview',
+       'wikilove-button-send' => 'Send WikiLove',
+       'wikilove-type-makeyourown' => 'Make your own',
 );
-

Modified: trunk/extensions/WikiLove/WikiLove.php
===================================================================
--- trunk/extensions/WikiLove/WikiLove.php      2011-05-02 20:30:38 UTC (rev 
87293)
+++ trunk/extensions/WikiLove/WikiLove.php      2011-05-02 20:34:52 UTC (rev 
87294)
@@ -21,7 +21,7 @@
 /**
  * @file
  * @ingroup Extensions
- * @author Ryan Kaldari
+ * @author Ryan Kaldari, Jan Paul Posma
  */
 
 # Alert the user that this is not a valid entry point to MediaWiki if they try 
to access the file directly.
@@ -40,29 +40,64 @@
        'version' => '0.1',
        'url' => 'http://www.mediawiki.org/wiki/Extension:WikiLove',
        'author' => array(
-               'Ryan Kaldari'
+               'Ryan Kaldari', 'Jan Paul Posma'
        ),
        'descriptionmsg' => 'wikilove-desc',
 );
 
+// current directory including trailing slash
 $dir = dirname( __FILE__ ) . '/';
 
-$wgHooks['LoadExtensionSchemaUpdates'][] = 'efWikiLoveSchema';
+// add autoload classes
+$wgAutoloadClasses['WikiLoveApi']                 = $dir . 'WikiLove.api.php';
+$wgAutoloadClasses['WikiLoveHooks']               = $dir . 
'WikiLove.hooks.php';
 
-$wgExtensionMessagesFiles['WikiLove'] = $dir . 'WikiLove.i18n.php';
+// i18n messages
+$wgExtensionMessagesFiles['WikiLove']             = $dir . 'WikiLove.i18n.php';
 
-function efWikiLoveSchema( $updater = null ) {
-       $dir = dirname( __FILE__ ) . '/';
-       if ( $updater === null ) {
-               global $wgDBtype, $wgExtNewTables;
+// register hooks
+$wgHooks['GetPreferences'][]                      = 
'WikiLoveHooks::getPreferences';
+$wgHooks['SkinTemplateNavigation'][]              = 
'WikiLoveHooks::skinTemplateNavigation';
+$wgHooks['SkinTemplateTabs'][]                    = 
'WikiLoveHooks::skinTemplateTabs';
+$wgHooks['BeforePageDisplay'][]                   = 
'WikiLoveHooks::beforePageDisplay';
+//$wgHooks['LoadExtensionSchemaUpdates'][]          = 
'WikiLoveHooks::loadExtensionSchemaUpdates';
+// Not a final schema, please apply patches/WikiLoveLog.sql manually for now!
 
-               if ( $wgDBtype == 'mysql' ) {
-                       $wgExtNewTables[] = array( 'wikilove_log', $dir . 
'WikiLove.sql' );
-               }
-       } else {
-               if ( $updater->getDB()->getType() == 'mysql' ) {
-                       $updater->addExtensionUpdate( array( 'addTable', 
'wikilove_log', $dir . 'WikiLove.sql', true ) );
-               }
-       }
-       return true;
-}
+// api modules
+$wgAPIModules['wikiLove'] = 'WikiLoveApi';
+
+// default user options
+$wgWikiLoveTabIcon = true;
+
+// resources
+$wikiLoveTpl = array(
+       'localBasePath' => dirname( __FILE__ ),
+       'remoteExtPath' => 'WikiLove',
+       'group'         => 'ext.wikiLove',
+);
+
+$wgResourceModules += array(
+       'ext.wikiLove' => $wikiLoveTpl + array(
+               'scripts'      => 'wikiLove.js',
+               'styles'       => 'wikiLove.css',
+               'messages' => array(
+                       'wikilove-dialog-title',
+                       'wikilove-select-type',
+                       'wikilove-add-details',
+                       'wikilove-title',
+                       'wikilove-enter-message',
+                       'wikilove-omit-sig',
+                       'wikilove-button-preview',
+                       'wikilove-preview',
+                       'wikilove-button-send',
+                       'wikilove-type-makeyourown',
+               ),
+               'dependencies' => array(
+                       'jquery.ui.dialog',
+                       'jquery.elastic',
+               ),
+       ),
+       'jquery.elastic' => $wikiLoveTpl + array(
+               'scripts' => 'jquery.elastic.js',
+       ),
+);

Deleted: trunk/extensions/WikiLove/WikiLove.sql
===================================================================
--- trunk/extensions/WikiLove/WikiLove.sql      2011-05-02 20:30:38 UTC (rev 
87293)
+++ trunk/extensions/WikiLove/WikiLove.sql      2011-05-02 20:34:52 UTC (rev 
87294)
@@ -1,11 +0,0 @@
-CREATE TABLE IF NOT EXISTS /*$wgDBprefix*/wikilove_log (
-       `wl_id` int NOT NULL PRIMARY KEY auto_increment,
-       `wl_timestamp` char(14) NOT NULL,
-       `wl_sender_id` int(11) NOT NULL,
-       `wl_receiver_id` int(11) NOT NULL,
-       `wl_wiki` varchar(64) NOT NULL,
-       `wl_type` varchar(64) NOT NULL,
-       `wl_template` varchar(64) NOT NULL,
-       `wl_message` varchar(255) NOT NULL,
-       `wl_email` bool NOT NULL default '0'
-) /*$wgDBTableOptions*/;

Added: trunk/extensions/WikiLove/images/heart-hover.png
===================================================================
(Binary files differ)


Property changes on: trunk/extensions/WikiLove/images/heart-hover.png
___________________________________________________________________
Added: svn:mime-type
   + image/png

Added: trunk/extensions/WikiLove/images/heart-icons.png
===================================================================
(Binary files differ)


Property changes on: trunk/extensions/WikiLove/images/heart-icons.png
___________________________________________________________________
Added: svn:mime-type
   + image/png

Added: trunk/extensions/WikiLove/images/spinner.gif
===================================================================
(Binary files differ)


Property changes on: trunk/extensions/WikiLove/images/spinner.gif
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: trunk/extensions/WikiLove/images/tab-break.png
===================================================================
(Binary files differ)


Property changes on: trunk/extensions/WikiLove/images/tab-break.png
___________________________________________________________________
Added: svn:mime-type
   + image/png

Added: trunk/extensions/WikiLove/jquery.elastic.js
===================================================================
--- trunk/extensions/WikiLove/jquery.elastic.js                         (rev 0)
+++ trunk/extensions/WikiLove/jquery.elastic.js 2011-05-02 20:34:52 UTC (rev 
87294)
@@ -0,0 +1,6 @@
+(function(jQuery){jQuery.fn.extend({elastic:function(){var 
mimics=['paddingTop','paddingRight','paddingBottom','paddingLeft','fontSize','lineHeight','fontFamily','width','fontWeight'];return
 this.each(function(){if(this.type!='textarea'){return false;}
+var $textarea=jQuery(this),$twin=jQuery('<div 
/>').css({'position':'absolute','display':'none','word-wrap':'break-word'}),lineHeight=parseInt($textarea.css('line-height'),10)||parseInt($textarea.css('font-size'),'10'),minheight=parseInt($textarea.css('height'),10)||lineHeight*3,maxheight=parseInt($textarea.css('max-height'),10)||Number.MAX_VALUE,goalheight=0,i=0;if(maxheight<0){maxheight=Number.MAX_VALUE;}
+$twin.appendTo($textarea.parent());var 
i=mimics.length;while(i--){$twin.css(mimics[i].toString(),$textarea.css(mimics[i].toString()));}
+function 
setHeightAndOverflow(height,overflow){curratedHeight=Math.floor(parseInt(height,10));if($textarea.height()!=curratedHeight){$textarea.css({'height':curratedHeight+'px','overflow':overflow});}}
+function update(){var 
textareaContent=$textarea.val().replace(/&/g,'&amp;').replace(/  
/g,'&nbsp;').replace(/<|>/g,'&gt;').replace(/\n/g,'<br />');var 
twinContent=$twin.html();if(textareaContent+'&nbsp;'!=twinContent){$twin.html(textareaContent+'&nbsp;');if(Math.abs($twin.height()+lineHeight-$textarea.height())>3){var
 
goalheight=$twin.height()+lineHeight;if(goalheight>=maxheight){setHeightAndOverflow(maxheight,'auto');}else
 
if(goalheight<=minheight){setHeightAndOverflow(minheight,'hidden');}else{setHeightAndOverflow(goalheight,'hidden');}}}}
+$textarea.css({'overflow':'hidden'});$textarea.keyup(function(){update();});$textarea.live('input
 paste',function(e){setTimeout(update,250);});update();});}});})(jQuery);
\ No newline at end of file


Property changes on: trunk/extensions/WikiLove/jquery.elastic.js
___________________________________________________________________
Added: svn:eol-style
   + native

Added: trunk/extensions/WikiLove/patches/WikiLoveLog.sql
===================================================================
--- trunk/extensions/WikiLove/patches/WikiLoveLog.sql                           
(rev 0)
+++ trunk/extensions/WikiLove/patches/WikiLoveLog.sql   2011-05-02 20:34:52 UTC 
(rev 87294)
@@ -0,0 +1,17 @@
+--
+-- WikiLove logging schema
+-- Not final, please apply this patch manually for now!
+--
+
+CREATE TABLE IF NOT EXISTS /*_*/wikilove_log (
+       `wl_id` int NOT NULL PRIMARY KEY auto_increment,
+       `wl_timestamp` binary(14) NOT NULL,
+       `wl_sender_id` int(11) NOT NULL,
+       `wl_receiver_id` int(11) NOT NULL,
+       `wl_wiki` varchar(64) NOT NULL,
+       `wl_type` varchar(64) NOT NULL,
+       `wl_template` varchar(64) NOT NULL,
+       `wl_subject` blob NOT NULL,
+       `wl_message` blob NOT NULL,
+       `wl_email` bool NOT NULL default '0'
+) /*$wgDBTableOptions*/;


Property changes on: trunk/extensions/WikiLove/patches/WikiLoveLog.sql
___________________________________________________________________
Added: svn:eol-style
   + native

Added: trunk/extensions/WikiLove/wikiLove.css
===================================================================
--- trunk/extensions/WikiLove/wikiLove.css                              (rev 0)
+++ trunk/extensions/WikiLove/wikiLove.css      2011-05-02 20:34:52 UTC (rev 
87294)
@@ -0,0 +1,149 @@
+/* include fix from r87101 here for older versions */
+div.vectorTabs span {
+       display: inline-block;
+       /* @embed */
+       background-image: url(images/tab-break.png);
+       background-position: bottom right;
+       background-repeat: no-repeat;
+}
+
+div.vectorTabs li a {
+       background-image: none;
+}
+
+#ca-unwatch.icon,
+#ca-watch.icon {
+       margin-right: 0px;
+}
+
+/* icon style */
+#ca-wikilove.icon a {
+       margin: 0;
+       padding: 0;
+       outline: none;
+       display: block;
+       width: 26px;
+       /* This hides the text but shows the background image */
+       padding-top: 3.1em;
+       margin-top: 0;
+       /* Only applied in IE6 */
+       margin-top: -0.8em !ie;
+       height: 0;
+       overflow: hidden;
+       /* @embed */
+       background-image: url(images/heart-icons.png);
+}
+#ca-wikilove.icon a {
+       background-position: 5px 60%;
+}
+#ca-wikilove.icon a:hover,
+#ca-wikilove.icon a:focus {
+       background-position: -19px 60%;
+}
+
+/* dialog */
+#wikiLoveDialog {
+       margin: 10px;
+}
+
+/* dialog type selection */
+#wikiLoveDialog #wlSelectType {
+       float: left;
+       width: 250px;
+}
+
+#wikiLoveDialog #wlSelectType ul {
+       list-style: none;
+       margin: 0;
+       padding: 0;
+}
+
+#wikiLoveDialog #wlSelectType ul li {
+       display: block;
+       background-color: #3060b0;
+       width: 250px;
+       padding: 10px 0;
+       
+       /* create a hand cursor, cross-browser hack: 
http://www.quirksmode.org/css/cursor.html */
+       cursor: pointer;
+       cursor: hand;
+}
+
+/* IGNORED BY IE6 */
+#wikiLoveDialog #wlSelectType ul > li {
+       display: inline-block;
+}
+
+#wikiLoveDialog #wlSelectType ul li:hover,
+#wikiLoveDialog #wlSelectType ul li:focus {
+       background-color: #3366bb;
+}
+
+#wikiLoveDialog #wlSelectType ul li.selected {
+       background-color: #e46020;
+}
+
+#wikiLoveDialog #wlSelectType ul li span {
+       font-size: 1.2em;
+       font-weight: bold;
+       text-decoration: none;
+       color: white;
+       margin-left: 10px;
+}
+
+/* dialog add details */
+#wikiLoveDialog #wlAddDetails {
+       float: right;
+       width: 480px;
+}
+
+#wikiLoveDialog #wlAddDetails label {
+       font-weight: bold;
+       font-size: 1.1em;
+}
+
+#wikiLoveDialog #wlAddDetails .text {
+       display: block;
+       width: 300px;
+}
+
+#wikiLoveDialog #wlAddDetails .wlOmitSig {
+       font-weight: light;
+       font-size: 0.9em;
+       float: right;
+       color: #999;
+}
+
+#wikiLoveDialog #wlAddDetails input,
+#wikiLoveDialog #wlAddDetails textarea,
+#wikiLoveDialog #wlAddDetails select {
+       margin-top: 5px;
+       margin-left: 15px;
+       max-width: 460px;
+       display: block;
+}
+
+#wikiLoveDialog .wlSpinner {
+       float: right;
+       margin-top: 6px;
+       display: none;
+}
+
+/* dialog preview */
+#wikiLoveDialog #wlPreview {
+       float: right;
+       width: 480px;
+}
+
+#wikiLoveDialog #wlPreview div {
+       margin-left: 15px;
+}
+
+#wikiLoveDialog #wlPreview .editsection {
+       display: none;
+}
+
+/* dialog misc */
+#wikiLoveDialog .submit {
+       float: right;
+}
\ No newline at end of file


Property changes on: trunk/extensions/WikiLove/wikiLove.css
___________________________________________________________________
Added: svn:eol-style
   + native

Added: trunk/extensions/WikiLove/wikiLove.js
===================================================================
--- trunk/extensions/WikiLove/wikiLove.js                               (rev 0)
+++ trunk/extensions/WikiLove/wikiLove.js       2011-05-02 20:34:52 UTC (rev 
87294)
@@ -0,0 +1,319 @@
+( function( $ ) { $.wikiLove = {
+       types: {
+               // example type, could be removed later (also no i18n)
+               'barnstar': {
+                       descr: 'Barnstar', // description in the types menu
+                       select: 'Select a barnstar:', // subtype select label
+                       subtypes: { // some different subtypes
+                               // note that when not using subtypes you should 
use these subtype options
+                               // for the top-level type
+                               'original': {
+                                       title: 'An Original Barnstar for you!', 
// subject title for the message
+                                       descr: 'Original barnstar', // 
description in the menu
+                                       text: '{{subst:The Original Barnstar|$1 
~~~~}}', // message text, $1 is replaced by the user message
+                                       template: 'The Original Barnstar' // 
template that is used, for statistics
+                               },
+                               'special': {
+                                       title: null, // no predefined title, 
allows the user to enter a title
+                                       descr: 'Special barnstar',
+                                       text: '{{subst:The Special Barnstarl|$1 
~~~~}}',
+                                       template: 'The Special Barnstar'
+                               }
+                       }
+               },
+               // default type, nice to leave this one in place when adding 
other types
+               'makeyourown': {
+                       title: null,
+                       descr: mw.msg( 'wikilove-type-makeyourown' ),
+                       text: "$1\n\n~~~~",
+                       template: ''
+               }
+       },
+       $dialog: null, // dialog jQuery object
+       editToken: '', // edit token used for the final AJAX call
+       currentTypeId: null, // id of the currently selected type (e.g. 
'barnstar' or 'makeyourown')
+       currentSubtypeId: null, // id of the currently selected subtype (e.g. 
'original' or 'special')
+       currentTypeOrSubtype: null, // content of the current (sub)type (i.e. 
an object with title, descr, text, etc.)
+       
+       /*
+        * Opens the dialog and builds it if necessary.
+        */
+       openDialog: function() {
+               if ( $.wikiLove.$dialog === null ) {
+                       // Build a type list like this:
+                       // <ul id="wlTypes">
+                       //   <li tabindex="0"><span>Barnstar</span></li>
+                       //   <li tabindex="0"><span>Make your own</span></li>
+                       // </ul>
+                       var $typeList = $( '<ul id="wlTypes"></ul>' );
+                       for( var typeId in $.wikiLove.types ) {
+                               $typeList.append(
+                                       $( '<li tabindex="0"><span>' + 
$.wikiLove.types[typeId].descr + '</span></li>' )
+                                       .data( 'typeId', typeId )
+                               );
+                       }
+                       
+                       // Build the left menu for selecting a type:
+                       // <div id="wlSelectType">
+                       //   <h3>Select Type:</h3>
+                       //   <ul id="wlTypes">...</ul>
+                       // </div>
+                       var $selectType = $( '<div id="wlSelectType"></div>' )
+                               .append( '<h3>' + mw.msg( 
'wikilove-select-type' ) + '</h3>' )
+                               .append( $typeList );
+                       
+                       // Build the right top section for selecting a subtype 
and entering a title (optional) and message
+                       // <div id="wlAddDetails">
+                       //   <h3>Add Details:</h3>
+                       //
+                       //   <label for="wlSubtype" 
id="wlSubtypeLabel">...</label>   (label depends on type)
+                       //   <select id="wlSubtype">...</select>                
      (also depends on type)
+                       //
+                       //   <label for="wlTitle" 
id="wlTitleLabel">Title:</label>    (hidden for some (sub)types)
+                       //   <input type="text" class="text" id="wlTitle"/>
+                       //
+                       //   <label for="wlMessage" id="wlMessageLabel">Enter a 
message:</label>
+                       //   <span class="wlOmitSig">(without a 
signature)</span>     (this span floats right)
+                       //   <textarea id="wlMessage"></textarea>               
      (textarea grows automatically with content)
+                       //
+                       //   <input id="wlButtonPreview" class="submit" 
type="submit" value="Preview"/>
+                       //   <img class="wlSpinner" src="..."/>                 
      (spinner for the preview button)
+                       // </div>
+                       var $addDetails = $( '<div id="wlAddDetails"></div>' )
+                               .append( '<h3>' + mw.msg( 
'wikilove-add-details' ) + '</h3>' )
+                               .append( '<label for="wlSubtype" 
id="wlSubtypeLabel"></label>' )
+                               .append( '<select id="wlSubtype"></select>' )   
                        
+                               .append( '<label for="wlTitle" 
id="wlTitleLabel">' + mw.msg( 'wikilove-title' ) + '</label>'  )
+                               .append( '<input type="text" class="text" 
id="wlTitle"/>' )
+                               .append( '<label for="wlMessage" 
id="wlMessageLabel">' + mw.msg( 'wikilove-enter-message' ) + '</label>'  )
+                               .append( '<span class="wlOmitSig">' + mw.msg( 
'wikilove-omit-sig' ) + '</span>'  )
+                               .append( '<textarea id="wlMessage"></textarea>' 
)
+                               .append( '<input id="wlButtonPreview" 
class="submit" type="submit" value="'
+                                       + mw.msg( 'wikilove-button-preview' ) + 
'"/>' )
+                               .append( '<img class="wlSpinner" src="' + 
mw.config.get( 'wgServer' ) + mw.config.get( 'wgScriptPath' )
+                                       + 
'/extensions/WikiLove/images/spinner.gif"/>' )
+                               .hide();
+                       
+                       // Build the right bottom preview section
+                       // <div id="wlPreview">
+                       //   <h3>Preview:</h3>
+                       //   <div id="wlPreviewArea">...</div>                  
      (preview gets loaded here)
+                       //   <input id="wlButtonSend" class="submit" 
type="submit" value="Send WikiLove"/>
+                       //   <img class="wlSpinner" src="..."/>                 
      (another spinner for the send button)
+                       // </div>
+                       var $preview = $( '<div id="wlPreview"></div>' )
+                               .append( '<h3>' + mw.msg( 'wikilove-preview' ) 
+ '</h3>' )
+                               .append( '<div id="wlPreviewArea"></div>' )
+                               .append( '<input id="wlButtonSend" 
class="submit" type="submit" value="'
+                                       + mw.msg( 'wikilove-button-send' ) + 
'"/>' )
+                               .append( '<img class="wlSpinner" src="' + 
mw.config.get( 'wgServer' ) + mw.config.get( 'wgScriptPath' )
+                                       + 
'/extensions/WikiLove/images/spinner.gif"/>' )
+                               .hide();
+                       
+                       // Build a modal, hidden dialog with the 3 different 
sections
+                       $.wikiLove.$dialog = $( '<div 
id="wikiLoveDialog"></div>' )
+                               .append( $selectType )
+                               .append( $addDetails )
+                               .append( $preview )
+                               .dialog({
+                                       width: 800,
+                                       autoOpen: false,
+                                       title: mw.msg( 'wikilove-dialog-title' 
),
+                                       modal: true,
+                                       resizable: false
+                               });
+
+                       $( '#wlMessage' ).elastic(); // have the message 
textarea grow automatically
+                       $( '#wlTypes li' ).click( $.wikiLove.clickType );
+                       $( '#wlSubtype' ).change( $.wikiLove.changeSubtype );
+                       $( '#wlButtonPreview' ).click( $.wikiLove.clickPreview 
);
+                       $( '#wlButtonSend' ).click( $.wikiLove.clickSend );
+               }
+               
+               $.wikiLove.$dialog.dialog( 'open' );
+       },
+       
+       /*
+        * Handler for the left menu. Selects a new type and initialises next 
section
+        * depending on whether or not to show subtypes.
+        */
+       clickType: function( e ) {
+               e.preventDefault();
+               
+               var newTypeId = $( this ).data( 'typeId' );
+               if( $.wikiLove.currentTypeId != newTypeId ) { // only do stuff 
when a different type is selected
+                       $.wikiLove.currentTypeId = newTypeId;
+                       $.wikiLove.currentSubtypeId = null; // reset the 
subtype id
+                       
+                       $( '#wlTypes li' ).removeClass( 'selected' );
+                       $( this ).addClass( 'selected' ); // highlight the new 
type in the menu
+                       
+                       if( typeof 
$.wikiLove.types[$.wikiLove.currentTypeId].subtypes == 'object' ) {
+                               // we're dealing with subtypes here
+                               $.wikiLove.currentTypeOrSubtype = null; // 
reset the (sub)type object until a subtype is selected
+                               $( '#wlSubtype' ).html( '' ); // clear the 
subtype menu
+                               
+                               for( var subtypeId in 
$.wikiLove.types[$.wikiLove.currentTypeId].subtypes ) {
+                                       // add all the subtypes to the menu 
while setting their subtype ids in jQuery data
+                                       var subtype = 
$.wikiLove.types[$.wikiLove.currentTypeId].subtypes[subtypeId];
+                                       $( '#wlSubtype' ).append(
+                                               $( '<option>' + subtype.descr + 
'</option>' ).data( 'subtypeId', subtypeId )
+                                       );
+                               }
+                               $( '#wlSubtype' ).show();
+                               
+                               // change and show the subtype label depending 
on the type
+                               $( '#wlSubtypeLabel' ).text( 
$.wikiLove.types[$.wikiLove.currentTypeId].select );
+                               $( '#wlSubtypeLabel' ).show();
+                               $.wikiLove.changeSubtype(); // update controls 
depending on the currently selected (i.e. first) subtype
+                       }
+                       else {
+                               // there are no subtypes, just use this type 
for the current (sub)type
+                               $.wikiLove.currentTypeOrSubtype = 
$.wikiLove.types[$.wikiLove.currentTypeId];
+                               $( '#wlSubtype' ).hide();
+                               $( '#wlSubtypeLabel' ).hide();
+                               $.wikiLove.updateAllDetails(); // update 
controls depending on this type
+                       }
+                       
+                       $( '#wlAddDetails' ).show();
+                       $( '#wlPreview' ).hide();
+               }
+               return false;
+       },
+       
+       /*
+        * Handler for changing the subtype.
+        */
+       changeSubtype: function() {
+               // find out which subtype is selected
+               var newSubtypeId = $( '#wlSubtype option:selected' 
).first().data( 'subtypeId' );
+               if( $.wikiLove.currentSubtypeId != newSubtypeId ) { // only 
change stuff when a different subtype is selected
+                       $.wikiLove.currentSubtypeId = newSubtypeId;
+                       $.wikiLove.currentTypeOrSubtype = 
$.wikiLove.types[$.wikiLove.currentTypeId]
+                               .subtypes[$.wikiLove.currentSubtypeId];
+                       $.wikiLove.updateAllDetails();
+                       $( '#wlPreview' ).hide();
+               }
+       },
+       
+       /*
+        * Called when type or subtype changes, updates controls. Currently 
only updates title label and textbox.
+        */
+       updateAllDetails: function() {
+               // show or hide title label and textbox depending on whether a 
predefined title exists
+               if( typeof $.wikiLove.currentTypeOrSubtype.title == 'string' ) {
+                       $( '#wlTitleLabel').hide();
+                       $( '#wlTitle' ).hide();
+                       $( '#wlTitle' ).val( 
$.wikiLove.currentTypeOrSubtype.title );
+               }
+               else {
+                       $( '#wlTitleLabel').show();
+                       $( '#wlTitle' ).show();
+                       $( '#wlTitle' ).val( '' );
+               }
+       },
+       
+       /*
+        * Handler for clicking the preview button. Builds data for AJAX 
request.
+        */
+       clickPreview: function() {
+               var title = '==' + $( '#wlTitle' ).val() + "==\n";
+               var msg = $.wikiLove.currentTypeOrSubtype.text.replace( '$1', 
$( '#wlMessage' ).val() );
+               $.wikiLove.doPreview( title + msg );
+       },
+       
+       /*
+        * Fires AJAX request for previewing wikitext.
+        */
+       doPreview: function( wikitext ) {
+               $( '#wlAddDetails .wlSpinner' ).fadeIn( 200 );
+               $.ajax({
+                       url: mw.config.get( 'wgServer' ) + mw.config.get( 
'wgScriptPath' ) + '/api.php?',
+                       data: {
+                               'action': 'parse',
+                               'format': 'json',
+                               'text': wikitext,
+                               'prop': 'text',
+                               'pst': true
+                       },
+                       dataType: 'json',
+                       type: 'POST',
+                       success: function( data ) {
+                               $.wikiLove.showPreview( data.parse.text['*'] );
+                               $( '#wlAddDetails .wlSpinner' ).fadeOut( 200 );
+                       }
+               });
+       },
+       
+       /*
+        * Callback for the preview function. Sets the preview area with the 
HTML and fades it in.
+        */
+       showPreview: function( html ) {
+               $( '#wlPreviewArea' ).html( html );
+               $( '#wlPreview' ).fadeIn( 200 );
+       },
+       
+       /*
+        * Handler for the send (final submit) button. Builds data for AJAX 
request.
+        * The type sent for statistics is 'typeId-subtypeId' when using 
subtypes,
+        * or simply 'typeId' otherwise.
+        */
+       clickSend: function() {
+               var title = $( '#wlTitle' ).val();
+               var msg = $.wikiLove.currentTypeOrSubtype.text.replace( '$1', 
$( '#wlMessage' ).val() );
+               $.wikiLove.doSend( title, msg, $.wikiLove.currentTypeId
+                       + ($.wikiLove.currentSubtypeId == null ? '-' + 
$.wikiLove.currentSubtypeId : ''),
+                       $.wikiLove.currentTypeOrSubtype.template);
+       },
+       
+       /*
+        * Fires the final AJAX request and then redirects to the talk page 
where the content is added.
+        */
+       doSend: function( subject, wikitext, type, template ) {
+               $( '#wlPreview .wlSpinner' ).fadeIn( 200 );
+               $.ajax({
+                       url: mw.config.get( 'wgServer' ) + mw.config.get( 
'wgScriptPath' ) + '/api.php?',
+                       data: {
+                               'action': 'wikiLove',
+                               'format': 'json',
+                               'title': mw.config.get( 'wgPageName' ),
+                               'template': template,
+                               'type': type,
+                               'text': wikitext,
+                               'subject': subject,
+                               'token': $.wikiLove.editToken
+                       },
+                       dataType: 'json',
+                       type: 'POST',
+                       success: function( data ) {
+                               mw.log( data );
+                               mw.log( mw.config.get( 'wgPageName' ) );
+                               $( '#wlPreview .wlSpinner' ).fadeOut( 200 );
+                               
+                               if ( data.redirect.pageName == mw.config.get( 
'wgPageName' ) ) {
+                                       // unfortunately, when on the talk page 
we cannot reload and then
+                                       // jump to the correct section, because 
when we set the hash (#...)
+                                       // the page won't reload...
+                                       window.location.reload();
+                               }
+                               else {
+                                       window.location = mw.config.get( 
'wgArticlePath' ).replace('$1', data.redirect.pageName) 
+                                               + data.redirect.fragment;
+                               }
+                       }
+               });
+       },
+       
+       /*
+        * Init function which is called upon page load. Binds the WikiLove 
icon to opening the dialog.
+        */
+       init: function() {
+               $( '#ca-wikilove a' ).click( function( e ) {
+                       $.wikiLove.openDialog();
+                       e.preventDefault();
+                       return false;
+               });
+       }
+};
+$.wikiLove.init();
+} ) ( jQuery );
\ No newline at end of file


Property changes on: trunk/extensions/WikiLove/wikiLove.js
___________________________________________________________________
Added: svn:eol-style
   + native


_______________________________________________
MediaWiki-CVS mailing list
MediaWiki-CVS@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-cvs

Reply via email to