r97513 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r97512‎ | r97513 | r97514 >
Date:16:45, 19 September 2011
Author:krinkle
Status:resolved (Comments)
Tags:
Comment:
[ResourceLoader2] Merge SpecialGadgets w/ SpecialGadgetManager
* Starting by correcting module names, file names and references
* Fix bug from r96309. 'gadgetmanager-editor-prop-remove' isn't in the jquery plugin. It's specific to the gadget manager and passed from there to it.
* Using SpecialGadgetManager as base since it's been completely rewritten



TODO:
* Rename property 'hidden' to something more descriptive. The hidden-ness is only applicable to the preferences page. It should be named something like 'utility'.

* Add 'position' property to blob and drop down to editor
Modified paths:
  • /branches/RL2/extensions/Gadgets/Gadgets.i18n.php (modified) (history)
  • /branches/RL2/extensions/Gadgets/Gadgets.php (modified) (history)
  • /branches/RL2/extensions/Gadgets/SpecialGadgetManager.php (deleted) (history)
  • /branches/RL2/extensions/Gadgets/SpecialGadgets.php (replaced) (history)
  • /branches/RL2/extensions/Gadgets/modules/ext.gadgets.gadgetmanager.css (added) (history)
  • /branches/RL2/extensions/Gadgets/modules/ext.gadgets.gadgetmanager.js (added) (history)
  • /branches/RL2/extensions/Gadgets/modules/ext.gadgets.gadgetmanager.prejs.css (deleted) (history)
  • /branches/RL2/extensions/Gadgets/modules/ext.gadgets.gadgetmanager.ui.css (deleted) (history)
  • /branches/RL2/extensions/Gadgets/modules/ext.gadgets.gadgetmanager.ui.js (deleted) (history)
  • /branches/RL2/extensions/Gadgets/modules/ext.gadgets.prejs.css (added) (history)

Diff [purge]

Index: branches/RL2/extensions/Gadgets/SpecialGadgetManager.php
@@ -1,176 +0,0 @@
2 -<?php
3 -/**
4 - * SpecialPage for Gadget manager
5 - *
6 - * @file
7 - * @ingroup Extensions
8 - */
9 -
10 -class SpecialGadgetManager extends SpecialPage {
11 -
12 - public function __construct() {
13 - parent::__construct( 'GadgetManager' );
14 - }
15 -
16 - /**
17 - * @param $par String: Optionally the id of the gadget to show info for.
18 - */
19 - public function execute( $par ) {
20 - $out = $this->getOutput();
21 -
22 - $this->setHeaders();
23 - $out->setPagetitle( wfMsg( 'gadgetmanager-title' ) );
24 - $out->addModuleStyles( 'ext.gadgets.gadgetmanager.prejs' );
25 -
26 - // Only load ajax editor if user is allowed to edit
27 - if ( $this->getUser()->isAllowed( 'gadgets-definition-edit' ) ) {
28 - $out->addModules( 'ext.gadgets.gadgetmanager.ui' );
29 - }
30 -
31 - // Determine view
32 - if ( is_string( $par ) && $par !== '' ) {
33 - $html = $this->generateGadgetView( $par );
34 - } else {
35 - $html = $this->generateOverview();
36 - }
37 -
38 - $out->addHtml( $html );
39 - }
40 -
41 - /**
42 - * @return String: HTML
43 - */
44 - private function generateOverview() {
45 - global $wgGadgetEnableSharing;
46 -
47 - $repo = LocalGadgetRepo::singleton();
48 - $gadgetsByCategory = $repo->getGadgetsByCategory();
49 -
50 - // If there there are no gadgets at all, exit early.
51 - if ( !count( $gadgetsByCategory ) ) {
52 - $noGadgetsMsgHtml = Html::element( 'p',
53 - array(
54 - 'class' => 'mw-gadgetmanager-nogadgets'
55 - ), wfMessage( 'gadgetmanager-nogadgets' )->plain()
56 - );
57 - $this->getOutput()->addHtml( $noGadgetsMsgHtml );
58 - return;
59 - }
60 - // There is atleast one gadget, let's get started.
61 - $this->getOutput()->addWikiMsg( 'gadgetmanager-pagetext', SpecialPage::getTitleFor( 'Recentchanges' )->getFullURL('namespace=' . NS_GADGET_DEFINITION ) );
62 - $html = '';
63 -
64 - // Sort categories alphabetically
65 - // @todo Sort causes the key "''" to be at the top, it should be on the bottom.
66 - ksort( $gadgetsByCategory );
67 -
68 - foreach ( $gadgetsByCategory as $category => $gadgets ) {
69 - // Avoid broken or empty headings. Fallback to a special message
70 - // for uncategorized gadgets (e.g. gadgets with category '' ).
71 - if ( $category !== '' ) {
72 - $categoryTitle = $repo->getCategoryTitle( $category );
73 - } else {
74 - $categoryTitle = wfMessage( 'gadgetmanager-uncategorized' )->plain();
75 - }
76 -
77 - // Category header
78 - $html .= Html::element( 'h2',
79 - array( 'class' => 'mw-gadgetmanager-category' ),
80 - $categoryTitle
81 - );
82 -
83 - // Start per-category gadgets table
84 - $html .= '<table class="mw-gadgetmanager-gadgets mw-datatable sortable"><thead><tr>';
85 - $html .=
86 - '<th>' . wfMessage( 'gadgetmanager-tablehead-title' )->escaped()
87 - . '</th><th>' . wfMessage( 'gadgetmanager-tablehead-default' )->escaped()
88 - . '</th><th>' . wfMessage( 'gadgetmanager-tablehead-hidden' )->escaped()
89 - . '</th>';
90 - if ( $wgGadgetEnableSharing ) {
91 - $html .= '<th>' . wfMessage( 'gadgetmanager-tablehead-shared' )->escaped() . '</th>';
92 - }
93 - $html .= '<th>' . wfMessage( 'gadgetmanager-tablehead-lastmod' )->escaped() . '</th>';
94 - $html .= '</tr></thead><tbody>';
95 -
96 - // Populate table rows for the current category
97 - foreach ( $gadgets as $gadgetId => $gadget ) {
98 - $html .= '<tr>';
99 -
100 - $tickedCheckboxHtml = Html::element( 'input', array(
101 - 'type' => 'checkbox',
102 - 'disabled' => 'disabled',
103 - 'value' => 1,
104 - 'checked' => 'checked',
105 - ) );
106 -
107 - // Title
108 - $titleLink = Linker::link(
109 - $this->getTitle( $gadget->getId() ),
110 - $gadget->getTitleMessage(),
111 - array( 'data-gadget-id' => $gadget->getId() )
112 - );
113 - $html .= "<td class=\"mw-gadgetmanager-gadgets-title\">$titleLink</td>";
114 - // Default
115 - $html .= '<td class="mw-gadgetmanager-gadgets-default">'
116 - . ( $gadget->isEnabledByDefault() ? $tickedCheckboxHtml : '' ) . '</td>';
117 - // Hidden
118 - $html .= '<td class="mw-gadgetmanager-gadgets-hidden">'
119 - . ( $gadget->isHidden() ? $tickedCheckboxHtml : '' ) . '</td>';
120 - // Shared
121 - if ( $wgGadgetEnableSharing ) {
122 - $html .= '<td class="mw-gadgetmanager-gadgets-shared">'
123 - . ( $gadget->isShared() ? $tickedCheckboxHtml : '' ) . '</td>';
124 - }
125 -
126 - // Last modified
127 - $lastModText = '';
128 - $definitionTitle = Title::makeTitleSafe( NS_GADGET_DEFINITION, $gadget->getId() . '.js' );
129 - if ( $definitionTitle ) {
130 - $definitionRev = Revision::newFromTitle( $definitionTitle );
131 - if ( $definitionRev ) {
132 - $userLang = $this->getLang();
133 - $revTimestamp = $definitionRev->getTimestamp();
134 - $userText = $definitionRev->getUserText();
135 - $userLinks =
136 - Linker::userLink(
137 - $definitionRev->getUser(),
138 - $userText
139 - ) .
140 - Linker::userToolLinks(
141 - $definitionRev->getUser(),
142 - $userText
143 - );
144 - $lastModText = wfMsgExt(
145 - 'gadgetmanager-tablecell-lastmod',
146 - array( 'replaceafter', 'parseinline' ),
147 - array(
148 - $userLang->timeanddate( $revTimestamp, true ),
149 - $userLinks,
150 - $userLang->date( $revTimestamp, true ),
151 - $userLang->time( $revTimestamp, true ),
152 - $userText
153 - )
154 - );
155 - }
156 - $html .= "<td class=\"mw-gadgetmanager-gadgets-lastmod\">$lastModText</td>";
157 - }
158 -
159 - $html .= '</tr>';
160 - }
161 -
162 - // End of per-category gadgets table
163 - $html .= '</tbody></table>';
164 - }
165 -
166 - return $html;
167 - }
168 -
169 - /**
170 - * @return String: HTML
171 - */
172 - public function generateGadgetView( $gadgetId ) {
173 - return 'TODO - This page is about "'
174 - . htmlspecialchars( $gadgetId )
175 - . '". Also used as permalink from other places.';
176 - }
177 -}
Index: branches/RL2/extensions/Gadgets/Gadgets.i18n.php
@@ -29,11 +29,12 @@
3030 'gadgets-preference-description' => '$1: $2',
3131 'gadgets-sharedprefstext' => 'Below is a list of gadgets from other wikis. TODO: This needs more text',
3232
33 - # For Special:Gadgets (overview for users; titles, messages, description, exporting etc.)
 33+ # For Special:Gadgets
3434 'gadgets' => 'Gadgets',
3535 'gadgets-title' => 'Gadgets',
3636 'gadgets-pagetext' => "Below is a list of gadgets available on this wiki. Users can enable or disable these through their [[Special:Preferences#mw-prefsection-gadgets|preferences page]].
37 -This overview provides easy access to the system message pages that define each gadget's description and title.",
 37+This overview provides easy access to the system message pages that define each gadget's description and title. Welcome to the gadget management interface. Below is an overview of all the configurable options for this gadget. defined on this wiki. Users can opt in or opt out of these through their [[Special:Preferences#mw-prefsection-gadgets|preferences page]]. All modifications to gadget definitions can be followed in the [$1 recent changes]",
 38+ 'gadgets-nogadgets' => 'This wiki currently has no gadgets defined.',
3839 'gadgets-uses' => 'Uses',
3940 'gadgets-required-rights' => 'Requires the {{PLURAL:$2|$1 right|following rights: $1}}.',
4041 'gadgets-default' => 'Enabled for everyone by default.',
@@ -44,16 +45,9 @@
4546 go to Special:Import on destination wiki and upload it. You must have appropriate permissions on the destination wiki (including the right to edit in the {{ns:Gadget}} and {{ns:Gadget definition}} namespaces) and the import from file uploads must be enabled.',
4647 'gadgets-export-download' => 'Download',
4748
48 - # For Special:GadgetManager (for gadget definition management)
49 - 'gadgetmanager' => 'Gadget manager',
 49+ # For the ext.gadgets.gadgetmanager module
5050 'gadgetmanager-title' => 'Gadget management',
51 - 'gadgetmanager-pagetext' => 'Welcome to the gadget management interface. Below is an overview of all gadgets defined on this wiki. Users can opt in or opt out of these through their [[Special:Preferences#mw-prefsection-gadgets|preferences page]]. All modifications to gadget definitions can be followed in the [$1 recent changes].',
52 - 'gadgetmanager-nogadgets' => 'This wiki currently has no gadgets defined.',
5351 'gadgetmanager-uncategorized' => 'Uncategorized',
54 - 'gadgetmanager-tablehead-title' => 'Gadget title',
55 - 'gadgetmanager-tablehead-default' => 'Default',
56 - 'gadgetmanager-tablehead-hidden' => 'Hidden',
57 - 'gadgetmanager-tablehead-shared' => 'Shared',
5852 'gadgetmanager-tablehead-lastmod' => 'Last modified',
5953 'gadgetmanager-tablecell-lastmod' => '$1 by $2',
6054 'gadgetmanager-editor-title' => 'Editing $1:',
@@ -68,7 +62,7 @@
6963 'gadgetmanager-prop-messages' => 'Messages',
7064 'gadgetmanager-prop-category' => 'Category',
7165 'gadgetmanager-prop-rights' => 'Required user rights',
72 - 'gadgetmanager-prop-default' => 'Enable by default',
 66+ 'gadgetmanager-prop-default' => 'Enable for everyone by default',
7367 'gadgetmanager-prop-hidden' => 'Hide gadget',
7468 'gadgetmanager-prop-shared' => 'Share gadget',
7569 'gadgetmanager-prop-default-yes' => 'This gadget is loaded by default.',
Index: branches/RL2/extensions/Gadgets/Gadgets.php
@@ -125,10 +125,10 @@
126126 $wgAutoloadClasses['SpecialGadgetManager'] = $dir . 'SpecialGadgetManager.php';
127127 $wgAutoloadClasses['SpecialGadgets'] = $dir . 'SpecialGadgets.php';
128128
129 -#$wgSpecialPages['Gadgets'] = 'SpecialGadgets';
130 -#$wgSpecialPageGroups['Gadgets'] = 'wiki';
131 -$wgSpecialPages['GadgetManager'] = 'SpecialGadgetManager';
132 -$wgSpecialPageGroups['GadgetManager'] = 'wiki';
 129+$wgSpecialPages['Gadgets'] = 'SpecialGadgets';
 130+$wgSpecialPageGroups['Gadgets'] = 'wiki';
 131+#$wgSpecialPages['GadgetManager'] = 'SpecialGadgetManager';
 132+#$wgSpecialPageGroups['GadgetManager'] = 'wiki';
133133
134134 $wgAPIListModules['gadgetcategories'] = 'ApiQueryGadgetCategories';
135135 $wgAPIListModules['gadgets'] = 'ApiQueryGadgets';
@@ -140,8 +140,8 @@
141141 );
142142 $wgResourceModules += array(
143143 // Also loaded in if javascript disabled
144 - 'ext.gadgets.gadgetmanager.prejs' => $gadResourceTemplate + array(
145 - 'styles' => 'ext.gadgets.gadgetmanager.prejs.css',
 144+ 'ext.gadgets.prejs' => $gadResourceTemplate + array(
 145+ 'styles' => 'ext.gadgets.prejs.css',
146146 'position' => 'top',
147147 ),
148148 // Method to interact with API
@@ -153,14 +153,11 @@
154154 // jQuery plugin
155155 'jquery.createPropCloud' => $gadResourceTemplate + array(
156156 'scripts' => 'jquery.createPropCloud.js',
157 - 'messages' => array(
158 - 'gadgetmanager-editor-prop-remove',
159 - ),
160157 ),
161158 // Event handling, UI components, initiates on document ready
162 - 'ext.gadgets.gadgetmanager.ui' => $gadResourceTemplate + array(
163 - 'scripts' => 'ext.gadgets.gadgetmanager.ui.js',
164 - 'styles' => 'ext.gadgets.gadgetmanager.ui.css',
 159+ 'ext.gadgets.gadgetmanager' => $gadResourceTemplate + array(
 160+ 'scripts' => 'ext.gadgets.gadgetmanager.js',
 161+ 'styles' => 'ext.gadgets.gadgetmanager.css',
165162 'dependencies' => array(
166163 'ext.gadgets.api',
167164 'jquery.localize',
@@ -172,6 +169,7 @@
173170 ),
174171 'messages' => array(
175172 'gadgetmanager-editor-title',
 173+ 'gadgetmanager-editor-prop-remove',
176174 'gadgetmanager-editor-removeprop-tooltip',
177175 'gadgetmanager-editor-save',
178176 'gadgetmanager-editor-cancel',
Index: branches/RL2/extensions/Gadgets/SpecialGadgets.php
@@ -1,168 +1,176 @@
22 <?php
33 /**
4 - * Special:Gadgets, provides a preview of MediaWiki:Gadgets.
 4+ * SpecialPage for Gadget manager
55 *
66 * @file
7 - * @ingroup SpecialPage
8 - * @author Daniel Kinzler, brightbyte.de
9 - * @copyright © 2007 Daniel Kinzler
10 - * @license GNU General Public License 2.0 or later
 7+ * @ingroup Extensions
118 */
129
13 -if( !defined( 'MEDIAWIKI' ) ) {
14 - echo( "not a valid entry point.\n" );
15 - die( 1 );
16 -}
 10+class SpecialGadgetManager extends SpecialPage {
1711
18 -/**
19 - *
20 - */
21 -class SpecialGadgets extends SpecialPage {
 12+ public function __construct() {
 13+ parent::__construct( 'GadgetManager' );
 14+ }
2215
2316 /**
24 - * Constructor
 17+ * @param $par String: Optionally the id of the gadget to show info for.
2518 */
26 - function __construct() {
27 - parent::__construct( 'Gadgets', '', true );
28 - }
 19+ public function execute( $par ) {
 20+ $out = $this->getOutput();
2921
30 - /**
31 - * Main execution function
32 - * @param $par Parameters passed to the page
33 - */
34 - function execute( $par ) {
35 - $parts = explode( '/', $par );
36 - if ( count( $parts ) == 2 && $parts[0] == 'export' ) {
37 - $this->showExportForm( $parts[1] );
 22+ $this->setHeaders();
 23+ $out->setPagetitle( wfMsg( 'gadgetmanager-title' ) );
 24+ $out->addModuleStyles( 'ext.gadgets.gadgetmanager.prejs' );
 25+
 26+ // Only load ajax editor if user is allowed to edit
 27+ if ( $this->getUser()->isAllowed( 'gadgets-definition-edit' ) ) {
 28+ $out->addModules( 'ext.gadgets.gadgetmanager.ui' );
 29+ }
 30+
 31+ // Determine view
 32+ if ( is_string( $par ) && $par !== '' ) {
 33+ $html = $this->generateGadgetView( $par );
3834 } else {
39 - $this->showMainForm();
 35+ $html = $this->generateOverview();
4036 }
 37+
 38+ $out->addHtml( $html );
4139 }
42 -
 40+
4341 /**
44 - * Displays form showing the list of installed gadgets
 42+ * @return String: HTML
4543 */
46 - public function showMainForm() {
47 - global $wgOut, $wgUser, $wgLang, $wgContLang;
 44+ private function generateOverview() {
 45+ global $wgGadgetEnableSharing;
4846
49 - $skin = $wgUser->getSkin();
 47+ $repo = LocalGadgetRepo::singleton();
 48+ $gadgetsByCategory = $repo->getGadgetsByCategory();
5049
51 - $this->setHeaders();
52 - $wgOut->setPagetitle( wfMsg( "gadgets-title" ) );
53 - $wgOut->addWikiMsg( 'gadgets-pagetext' );
54 -
55 - $gadgets = Gadget::loadStructuredList();
56 - if ( !$gadgets ) return;
57 -
58 - $lang = "";
59 - if ( $wgLang->getCode() != $wgContLang->getCode() ) {
60 - $lang = "/" . $wgLang->getCode();
 50+ // If there there are no gadgets at all, exit early.
 51+ if ( !count( $gadgetsByCategory ) ) {
 52+ $noGadgetsMsgHtml = Html::element( 'p',
 53+ array(
 54+ 'class' => 'mw-gadgetmanager-nogadgets'
 55+ ), wfMessage( 'gadgetmanager-nogadgets' )->plain()
 56+ );
 57+ $this->getOutput()->addHtml( $noGadgetsMsgHtml );
 58+ return;
6159 }
 60+ // There is atleast one gadget, let's get started.
 61+ $this->getOutput()->addWikiMsg( 'gadgetmanager-pagetext', SpecialPage::getTitleFor( 'Recentchanges' )->getFullURL('namespace=' . NS_GADGET_DEFINITION ) );
 62+ $html = '';
 63+
 64+ // Sort categories alphabetically
 65+ // @todo Sort causes the key "''" to be at the top, it should be on the bottom.
 66+ ksort( $gadgetsByCategory );
6267
63 - $listOpen = false;
 68+ foreach ( $gadgetsByCategory as $category => $gadgets ) {
 69+ // Avoid broken or empty headings. Fallback to a special message
 70+ // for uncategorized gadgets (e.g. gadgets with category '' ).
 71+ if ( $category !== '' ) {
 72+ $categoryTitle = $repo->getCategoryTitle( $category );
 73+ } else {
 74+ $categoryTitle = wfMessage( 'gadgetmanager-uncategorized' )->plain();
 75+ }
6476
65 - $msgOpt = array( 'parseinline', 'parsemag' );
66 - $editInterfaceAllowed = $wgUser->isAllowed( 'editinterface' );
67 -
68 - foreach ( $gadgets as $section => $entries ) {
69 - if ( $section !== false && $section !== '' ) {
70 - $t = Title::makeTitleSafe( NS_MEDIAWIKI, "Gadget-section-$section$lang" );
71 - if ( $editInterfaceAllowed ) {
72 - $lnkTarget = $t
73 - ? $skin->link( $t, wfMsgHTML( 'edit' ), array(), array( 'action' => 'edit' ) )
74 - : htmlspecialchars( $section );
75 - $lnk = "&#160; &#160; [$lnkTarget]";
76 - } else {
77 - $lnk = '';
78 - }
79 - $ttext = wfMsgExt( "gadget-section-$section", $msgOpt );
 77+ // Category header
 78+ $html .= Html::element( 'h2',
 79+ array( 'class' => 'mw-gadgetmanager-category' ),
 80+ $categoryTitle
 81+ );
8082
81 - if( $listOpen ) {
82 - $wgOut->addHTML( Xml::closeElement( 'ul' ) . "\n" );
83 - $listOpen = false;
84 - }
85 - $wgOut->addHTML( Html::rawElement( 'h2', array(), $ttext . $lnk ) . "\n" );
 83+ // Start per-category gadgets table
 84+ $html .= '<table class="mw-gadgetmanager-gadgets mw-datatable sortable"><thead><tr>';
 85+ $html .=
 86+ '<th>' . wfMessage( 'gadgetmanager-tablehead-title' )->escaped()
 87+ . '</th><th>' . wfMessage( 'gadgetmanager-tablehead-default' )->escaped()
 88+ . '</th><th>' . wfMessage( 'gadgetmanager-tablehead-hidden' )->escaped()
 89+ . '</th>';
 90+ if ( $wgGadgetEnableSharing ) {
 91+ $html .= '<th>' . wfMessage( 'gadgetmanager-tablehead-shared' )->escaped() . '</th>';
8692 }
 93+ $html .= '<th>' . wfMessage( 'gadgetmanager-tablehead-lastmod' )->escaped() . '</th>';
 94+ $html .= '</tr></thead><tbody>';
8795
88 - foreach ( $entries as $gadget ) {
89 - $t = Title::makeTitleSafe( NS_MEDIAWIKI, "Gadget-{$gadget->getId()}$lang" );
90 - if ( !$t ) continue;
 96+ // Populate table rows for the current category
 97+ foreach ( $gadgets as $gadgetId => $gadget ) {
 98+ $html .= '<tr>';
9199
92 - $links = array();
93 - if ( $editInterfaceAllowed ) {
94 - $links[] = $skin->link( $t, wfMsgHTML( 'edit' ), array(), array( 'action' => 'edit' ) );
 100+ $tickedCheckboxHtml = Html::element( 'input', array(
 101+ 'type' => 'checkbox',
 102+ 'disabled' => 'disabled',
 103+ 'value' => 1,
 104+ 'checked' => 'checked',
 105+ ) );
 106+
 107+ // Title
 108+ $titleLink = Linker::link(
 109+ $this->getTitle( $gadget->getId() ),
 110+ $gadget->getTitleMessage(),
 111+ array( 'data-gadget-id' => $gadget->getId() )
 112+ );
 113+ $html .= "<td class=\"mw-gadgetmanager-gadgets-title\">$titleLink</td>";
 114+ // Default
 115+ $html .= '<td class="mw-gadgetmanager-gadgets-default">'
 116+ . ( $gadget->isEnabledByDefault() ? $tickedCheckboxHtml : '' ) . '</td>';
 117+ // Hidden
 118+ $html .= '<td class="mw-gadgetmanager-gadgets-hidden">'
 119+ . ( $gadget->isHidden() ? $tickedCheckboxHtml : '' ) . '</td>';
 120+ // Shared
 121+ if ( $wgGadgetEnableSharing ) {
 122+ $html .= '<td class="mw-gadgetmanager-gadgets-shared">'
 123+ . ( $gadget->isShared() ? $tickedCheckboxHtml : '' ) . '</td>';
95124 }
96 - $links[] = $skin->link( $this->getTitle( "export/{$gadget->getId()}" ), wfMsgHtml( 'gadgets-export' ) );
97 -
98 - $ttext = wfMsgExt( "gadget-{$gadget->getId()}", $msgOpt );
99125
100 - if( !$listOpen ) {
101 - $listOpen = true;
102 - $wgOut->addHTML( Xml::openElement( 'ul' ) );
 126+ // Last modified
 127+ $lastModText = '';
 128+ $definitionTitle = Title::makeTitleSafe( NS_GADGET_DEFINITION, $gadget->getId() . '.js' );
 129+ if ( $definitionTitle ) {
 130+ $definitionRev = Revision::newFromTitle( $definitionTitle );
 131+ if ( $definitionRev ) {
 132+ $userLang = $this->getLang();
 133+ $revTimestamp = $definitionRev->getTimestamp();
 134+ $userText = $definitionRev->getUserText();
 135+ $userLinks =
 136+ Linker::userLink(
 137+ $definitionRev->getUser(),
 138+ $userText
 139+ ) .
 140+ Linker::userToolLinks(
 141+ $definitionRev->getUser(),
 142+ $userText
 143+ );
 144+ $lastModText = wfMsgExt(
 145+ 'gadgetmanager-tablecell-lastmod',
 146+ array( 'replaceafter', 'parseinline' ),
 147+ array(
 148+ $userLang->timeanddate( $revTimestamp, true ),
 149+ $userLinks,
 150+ $userLang->date( $revTimestamp, true ),
 151+ $userLang->time( $revTimestamp, true ),
 152+ $userText
 153+ )
 154+ );
 155+ }
 156+ $html .= "<td class=\"mw-gadgetmanager-gadgets-lastmod\">$lastModText</td>";
103157 }
104 - $lnk = '&#160;&#160;' . wfMsg( 'parentheses', $wgLang->pipeList( $links ) );
105 - $wgOut->addHTML( Xml::openElement( 'li' ) .
106 - $ttext . $lnk . "<br />" .
107 - wfMsgHTML( 'gadgets-uses' ) . wfMsg( 'colon-separator' )
108 - );
109158
110 - $lnk = array();
111 - foreach ( $gadget->getScriptsAndStyles() as $codePage ) {
112 - $t = Title::makeTitleSafe( NS_MEDIAWIKI, $codePage );
113 - if ( !$t ) continue;
 159+ $html .= '</tr>';
 160+ }
114161
115 - $lnk[] = $skin->link( $t, htmlspecialchars( $t->getText() ) );
116 - }
117 - $wgOut->addHTML( $wgLang->commaList( $lnk ) );
118 - $rights = $gadget->getRequiredRights();
119 - if ( count( $rights ) ) {
120 - $wgOut->addHTML( '<br />' .
121 - wfMessage( 'gadgets-required-rights', $wgLang->commaList( $rights ), count( $rights ) )->parse()
122 - );
123 - }
124 - if ( $gadget->isOnByDefault() ) {
125 - $wgOut->addHTML( '<br />' . wfMessage( 'gadgets-default' )->parse() );
126 - }
127 -
128 - $wgOut->addHTML( Xml::closeElement( 'li' ) . "\n" );
129 - }
 162+ // End of per-category gadgets table
 163+ $html .= '</tbody></table>';
130164 }
131165
132 - if( $listOpen ) {
133 - $wgOut->addHTML( Xml::closeElement( 'ul' ) . "\n" );
134 - }
 166+ return $html;
135167 }
136168
137169 /**
138 - * Exports a gadget with its dependencies in a serialized form
139 - * @param $gadget String Name of gadget to export
 170+ * @return String: HTML
140171 */
141 - public function showExportForm( $gadget ) {
142 - global $wgOut, $wgScript;
143 -
144 - $gadgets = Gadget::loadList();
145 - if ( !isset( $gadgets[$gadget] ) ) {
146 - $wgOut->showErrorPage( 'error', 'gadgets-not-found', array( $gadget ) );
147 - return;
148 - }
149 -
150 - $g = $gadgets[$gadget];
151 - $this->setHeaders();
152 - $wgOut->setPagetitle( wfMsg( "gadgets-export-title" ) );
153 - $wgOut->addWikiMsg( 'gadgets-export-text', $gadget, $g->getDefinition() );
154 -
155 - $exportList = "MediaWiki:gadget-$gadget\n";
156 - foreach ( $g->getScriptsAndStyles() as $page ) {
157 - $exportList .= "MediaWiki:$page\n";
158 - }
159 -
160 - $wgOut->addHTML( Html::openElement( 'form', array( 'method' => 'get', 'action' => $wgScript ) )
161 - . Html::hidden( 'title', SpecialPage::getTitleFor( 'Export' )->getPrefixedDBKey() )
162 - . Html::hidden( 'pages', $exportList )
163 - . Html::hidden( 'wpDownload', '1' )
164 - . Html::hidden( 'templates', '1' )
165 - . Xml::submitButton( wfMsg( 'gadgets-export-download' ) )
166 - . Html::closeElement( 'form' )
167 - );
 172+ public function generateGadgetView( $gadgetId ) {
 173+ return 'TODO - This page is about "'
 174+ . htmlspecialchars( $gadgetId )
 175+ . '". Also used as permalink from other places.';
168176 }
169177 }
Index: branches/RL2/extensions/Gadgets/modules/ext.gadgets.gadgetmanager.ui.css
@@ -1,67 +0,0 @@
2 -/**
3 - * Styling for the gadget manager javascript-generated user interface.
4 - */
5 -
6 -/**
7 - * Form
8 - */
9 -.mw-gadgetmanager-form fieldset {
10 - margin: 0;
11 -}
12 -
13 -.mw-gadgetmanager-form table {
14 - width: 100%;
15 -}
16 -
17 -.mw-gadgetmanager-form td,
18 -.mw-gadgetmanager-form th {
19 - vertical-align: top;
20 -}
21 -
22 -/**
23 - * The PropCloud
24 - */
25 -.mw-gadgetmanager-propcloud {
26 - background: white;
27 - border: 1px solid grey;
28 - overflow: hidden;
29 -}
30 -
31 -.mw-gadgetmanager-propcontainer {}
32 -
33 -.mw-gadgetmanager-prop {
34 - float: left;
35 - margin: 2px 5px 5px 2px;
36 - padding: 2px 5px;
37 - background: #e5eff6;
38 - border: 1px solid #a4d2fb;
39 - border-radius: 10px;
40 - line-height: 1;
41 -}
42 -
43 -.mw-gadgetmanager-prop-label {}
44 -
45 -.mw-gadgetmanager-prop-delete {
46 - display: inline-block;
47 - width: 10px;
48 - height: 10px;
49 - /* @embed */
50 - background: url(images/close.png) 50% 50% no-repeat;
51 - opacity: 0.4;
52 -}
53 -
54 -.mw-gadgetmanager-prop:hover .mw-gadgetmanager-prop-delete {
55 - opacity: 0.7;
56 -}
57 -
58 -.mw-gadgetmanager-prop:hover .mw-gadgetmanager-prop-delete:hover {
59 - opacity: 1;
60 - cursor: pointer;
61 -}
62 -
63 -.mw-gadgetmanager-propinput,
64 -.mw-gadgetmanager-propinput:focus {
65 - border: 0;
66 - outline: 0;
67 - background: transparent;
68 -}
Index: branches/RL2/extensions/Gadgets/modules/ext.gadgets.gadgetmanager.ui.js
@@ -1,405 +0,0 @@
2 -/**
3 - * JavaScript to initialize the UI of the gadget manager.
4 - *
5 - * @author Timo Tijhof
6 - * @copyright © 2011 Timo Tijhof
7 - * @license GNU General Public Licence 2.0 or later
8 - */
9 -( function( $ ) {
10 -
11 - var
12 - /**
13 - * @var {Object} Local alias to mw.gadgets
14 - */
15 - ga = mw.gadgets,
16 - /**
17 - * @var {Object} HTML fragements
18 - */
19 - tpl = {
20 - fancyForm: '<form class="mw-gadgetmanager-form">\
21 - <fieldset>\
22 - <legend>Module properties</legend>\
23 - <table>\
24 - <tr>\
25 - <td><label for="mw-gadgetmanager-input-scripts"><html:msg key="gadgetmanager-prop-scripts"></label></td>\
26 - <td><input type="text" id="mw-gadgetmanager-input-scripts" /></td>\
27 - </tr>\
28 - <tr>\
29 - <td><label for="mw-gadgetmanager-input-styles"><html:msg key="gadgetmanager-prop-styles"></label></td>\
30 - <td><input type="text" id="mw-gadgetmanager-input-styles" /></td>\
31 - </tr>\
32 - <tr>\
33 - <td><label for="mw-gadgetmanager-input-dependencies"><html:msg key="gadgetmanager-prop-dependencies"></label></td>\
34 - <td><input type="text" id="mw-gadgetmanager-input-dependencies" /></td>\
35 - </tr>\
36 - <tr>\
37 - <td><label for="mw-gadgetmanager-input-messages"><html:msg key="gadgetmanager-prop-messages"></label></td>\
38 - <td><input type="text" id="mw-gadgetmanager-input-messages" /></td>\
39 - </tr>\
40 - </table>\
41 - </fieldset>\
42 - <fieldset>\
43 - <legend>Gadget settings</legend>\
44 - <table>\
45 - <tr>\
46 - <td><label for="mw-gadgetmanager-input-category"><html:msg key="gadgetmanager-prop-category"></label></td>\
47 - <td><select id="mw-gadgetmanager-input-category"></select></td>\
48 - </tr>\
49 - <tr>\
50 - <td><label for="mw-gadgetmanager-input-rights"><html:msg key="gadgetmanager-prop-rights"></label></td>\
51 - <td><input type="text" id="mw-gadgetmanager-input-rights" /></td>\
52 - </tr>\
53 - <tr>\
54 - <td><label for="mw-gadgetmanager-input-default"><html:msg key="gadgetmanager-prop-default"></label></td>\
55 - <td><input type="checkbox" id="mw-gadgetmanager-input-default" /></td>\
56 - </tr>\
57 - <tr>\
58 - <td><label for="mw-gadgetmanager-input-hidden"><html:msg key="gadgetmanager-prop-hidden"></label></td>\
59 - <td><input type="checkbox" id="mw-gadgetmanager-input-hidden" /></td>\
60 - </tr>\
61 - ' + ( ga.conf.enableSharing ? '<tr>\
62 - <td><label for="mw-gadgetmanager-input-shared"><html:msg key="gadgetmanager-prop-shared"></label></td>\
63 - <td><input type="checkbox" id="mw-gadgetmanager-input-shared" /></td>\
64 - </tr>\
65 - ' : '' ) + '</table>\
66 - </fieldset>\
67 - </form>'
68 - },
69 - /**
70 - * @var {Object} Static cache for suggestions by script prefix.
71 - */
72 - suggestCacheScripts = {},
73 - /**
74 - * @var {Object} Static cache for suggestions by style prefix.
75 - */
76 - suggestCacheStyles = {},
77 - /**
78 - * @var {Object} Static cache for suggestions by messages prefix.
79 - */
80 - suggestCacheMsgs = {},
81 - /**
82 - * @var {Object} Complete static cache for module names. Lazy loaded from null.
83 - */
84 - suggestCacheDependencies = null,
85 - /**
86 - * @var {Object} Complete static cache for all rights.
87 - */
88 - suggestCacheRights = ga.conf.allRights,
89 - /**
90 - * @var {Number} Maximum number of autocomplete suggestions in the gadget editor input fields.
91 - */
92 - suggestLimit = 7;
93 -
94 - /* Local functions */
95 -
96 - /**
97 - * Utility function to pad a zero
98 - * to single digit number. Used by ISODateString().
99 - * @param n {Number}
100 - * @return {String}
101 - */
102 - function pad( n ) {
103 - return n < 10 ? '0' + n : n;
104 - }
105 - /**
106 - * Format a date in an ISO 8601 format using UTC.
107 - * https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Date#Example:_ISO_8601_formatted_dates
108 - *
109 - * @param d {Date}
110 - * @return {String}
111 - */
112 - function ISODateString( d ) {
113 - return d.getUTCFullYear() + '-'
114 - + pad( d.getUTCMonth() + 1 ) + '-'
115 - + pad( d.getUTCDate() ) + 'T'
116 - + pad( d.getUTCHours() ) + ':'
117 - + pad( d.getUTCMinutes() ) + ':'
118 - + pad( d.getUTCSeconds() ) + 'Z';
119 - }
120 -
121 - /* Public functions */
122 -
123 - ga.ui = {
124 - /**
125 - * Initializes the the page. For now just binding click handlers
126 - * to the anchor tags in the table.
127 - */
128 - initUI: function() {
129 - // Bind trigger to the links
130 - $( '.mw-gadgetmanager-gadgets .mw-gadgetmanager-gadgets-title a' )
131 - .click( function( e ) {
132 - e.preventDefault();
133 - ga.ui.startGadgetEditor( $( this ).data( 'gadget-id' ) );
134 - });
135 - },
136 -
137 - /**
138 - * Initialize the gadget editor dialog.
139 - *
140 - * @asynchronous
141 - * @param gadgetId {String}
142 - */
143 - startGadgetEditor: function( gadgetId ) {
144 - // Ad hoc multi-loader. We need both requests, which are asynchronous,
145 - // to be complete. Which ever finishes first will set the local variable
146 - // to it's return value for the other callback to use.
147 - // @todo Notification: In case of an 'error'.
148 - var gadget, cats;
149 -
150 - ga.api.getGadgetCategories( function( ret ) {
151 - if ( gadget ) {
152 - // getGadgetData already done
153 - return ga.ui.showFancyForm( gadget, ret );
154 - }
155 - // getGadgetData not done yet, leave cats for it's callback to use
156 - cats = ret;
157 - });
158 -
159 - ga.api.getGadgetData( gadgetId, function( ret ) {
160 - if ( cats ) {
161 - // getGadgetCategories already done
162 - return ga.ui.showFancyForm( ret, cats );
163 - }
164 - // getGadgetCategories not done yet, leave gadget for it's callback to use
165 - gadget = ret;
166 - });
167 - },
168 -
169 - /**
170 - * Generate form, create a dialog and open it into view.
171 - *
172 - * @param gadget {Object} Gadget object of the gadget to be modified.
173 - * @param categories {Array} Gadget categories.
174 - * @return {jQuery} The (dialogged) form.
175 - */
176 - showFancyForm: function( gadget, categories ) {
177 - var $form = ga.ui.getFancyForm( gadget.metadata, categories ),
178 - buttons = {};
179 -
180 - // Form submit
181 - buttons[mw.msg( 'gadgetmanager-editor-save' )] = function() {
182 - ga.api.doModifyGadget( gadget, {
183 - starttimestamp: ISODateString( new Date() ),
184 - success: function( response ) {
185 - $form.dialog( 'close' );
186 - window.location.reload();
187 - },
188 - error: function( error ) {
189 - mw.log( 'mw.gadgets.api.doModifyGadget: error', error );
190 - // @todo Notification: $formNotif.add( .. );
191 - }
192 - });
193 - };
194 -
195 - return $form
196 - .dialog({
197 - autoOpen: true,
198 - width: 800,
199 - modal: true,
200 - draggable: false,
201 - resizable: false,
202 - title: mw.message( 'gadgetmanager-editor-title', gadget.title ).escaped(),
203 - buttons: buttons,
204 - open: function() {
205 - // Dialog is ready for action.
206 - // Push out any notifications if some were queued up already between
207 - // getting the gadget data and the display of the form.
208 -
209 - // @todo Notification: $formNotif.add( .. );
210 - }
211 - });
212 - },
213 -
214 - /**
215 - * Generate a <form> for the given module.
216 - * Also binds events for submission and autocompletion.
217 - *
218 - * @param metadata {Object} Object to read and write to, used when saving
219 - * the gadget metadata back through the API.
220 - * @param categories {Array} Gadget categories.
221 - * @return {jQuery} The form.
222 - */
223 - getFancyForm: function( metadata, categories ) {
224 - var nsGadgetId = mw.config.get( 'wgNamespaceIds' ).gadget,
225 - $form = $( tpl.fancyForm ).localize();
226 -
227 - // Module properties: scripts
228 - $form.find( '#mw-gadgetmanager-input-scripts' ).createPropCloud({
229 - props: metadata.module.scripts,
230 - autocompleteSource: function( data, response ) {
231 - // Use cache if available
232 - if ( data.term in suggestCacheScripts ) {
233 - response( suggestCacheScripts[data.term] );
234 - return;
235 - }
236 - $.getJSON( mw.util.wikiScript( 'api' ), {
237 - format: 'json',
238 - action: 'query',
239 - list: 'gadgetpages',
240 - gpnamespace: nsGadgetId,
241 - gpextension: 'js',
242 - gpprefix: data.term
243 - }, function( json ) {
244 - if ( json && json.query && json.query.gadgetpages ) {
245 - var suggestions = json.query.gadgetpages.splice( 0, suggestLimit );
246 - suggestions = $.map( suggestions, function( val, i ) {
247 - return val.pagename;
248 - });
249 -
250 - // Update cache
251 - suggestCacheScripts[data.term] = suggestions;
252 -
253 - response( suggestions );
254 - } else {
255 - response( [] );
256 - }
257 - }
258 - );
259 - },
260 - prefix: 'mw-gadgetmanager-',
261 - removeTooltip: mw.msg( 'gadgetmanager-editor-removeprop-tooltip' )
262 - });
263 -
264 - // Module properties: styles
265 - $form.find( '#mw-gadgetmanager-input-styles' ).createPropCloud({
266 - props: metadata.module.styles,
267 - autocompleteSource: function( data, response ) {
268 - // Use cache if available
269 - if ( data.term in suggestCacheStyles ) {
270 - response( suggestCacheStyles[data.term] );
271 - return;
272 - }
273 - $.getJSON( mw.util.wikiScript( 'api' ), {
274 - format: 'json',
275 - action: 'query',
276 - list: 'gadgetpages',
277 - gpnamespace: nsGadgetId,
278 - gpextension: 'css',
279 - gpprefix: data.term
280 - }, function( json ) {
281 - if ( json && json.query && json.query.gadgetpages ) {
282 - var suggestions = $.map( json.query.gadgetpages, function( val, i ) {
283 - return val.pagename;
284 - });
285 - suggestions = suggestions.splice( 0, suggestLimit );
286 -
287 - // Update cache
288 - suggestCacheStyles[data.term] = suggestions;
289 -
290 - response( suggestions );
291 - } else {
292 - response( [] );
293 - }
294 - }
295 - );
296 - },
297 - prefix: 'mw-gadgetmanager-',
298 - removeTooltip: mw.msg( 'gadgetmanager-editor-removeprop-tooltip' )
299 - });
300 -
301 - // Module properties: dependencies
302 - $form.find( '#mw-gadgetmanager-input-dependencies' ).createPropCloud({
303 - props: metadata.module.dependencies,
304 - autocompleteSource: function( data, response ) {
305 - if ( suggestCacheDependencies === null ) {
306 - suggestCacheDependencies = mw.loader.getModuleNames();
307 - }
308 - var output = $.ui.autocomplete.filter( suggestCacheDependencies, data.term );
309 - response( output.slice( 0, suggestLimit ) );
310 - },
311 - prefix: 'mw-gadgetmanager-',
312 - removeTooltip: mw.msg( 'gadgetmanager-editor-removeprop-tooltip' )
313 - });
314 -
315 - // Module properties: messages
316 - $form.find( '#mw-gadgetmanager-input-messages' ).createPropCloud({
317 - props: metadata.module.messages,
318 - autocompleteSource: function( data, response ) {
319 - // Use cache if available
320 - if ( data.term in suggestCacheMsgs ) {
321 - response( suggestCacheMsgs[data.term] );
322 - return;
323 - }
324 - $.getJSON( mw.util.wikiScript( 'api' ), {
325 - format: 'json',
326 - action: 'query',
327 - meta: 'allmessages',
328 - amprefix: data.term,
329 - amnocontent: true,
330 - amlang: mw.config.get( 'wgContentLanguage' )
331 - }, function( json ) {
332 - if ( json && json.query && json.query.allmessages ) {
333 - var suggestions = $.map( json.query.allmessages, function( val, i ) {
334 - return val.name;
335 - });
336 - suggestions = suggestions.splice( 0, suggestLimit );
337 -
338 - // Update cache
339 - suggestCacheMsgs[data.term] = suggestions;
340 -
341 - response( suggestions );
342 - } else {
343 - response( [] );
344 - }
345 - }
346 - );
347 - },
348 - prefix: 'mw-gadgetmanager-',
349 - removeTooltip: mw.msg( 'gadgetmanager-editor-removeprop-tooltip' )
350 - });
351 -
352 - // Gadget settings: category
353 - $form.find( '#mw-gadgetmanager-input-category' ).append( function() {
354 - var current = metadata.settings.category,
355 - opts = '',
356 - i = 0,
357 - cat;
358 - for ( ; i < categories.length; i++ ) {
359 - cat = categories[i];
360 - opts += mw.html.element( 'option', {
361 - value: cat.name,
362 - selected: cat.name === current
363 - }, cat.title );
364 - }
365 - return opts;
366 - }).change( function() {
367 - metadata.settings.category = $(this).val();
368 - });
369 -
370 - // Gadget settings: rights
371 - $form.find( '#mw-gadgetmanager-input-rights' ).createPropCloud({
372 - props: metadata.settings.rights,
373 - autocompleteSource: function( data, response ) {
374 - var output = $.ui.autocomplete.filter( suggestCacheRights, data.term );
375 - response( output.slice( 0, suggestLimit ) );
376 - },
377 - prefix: 'mw-gadgetmanager-',
378 - removeTooltip: mw.msg( 'gadgetmanager-editor-removeprop-tooltip' )
379 - });
380 -
381 - // Gadget settings: Default
382 - $form.find( '#mw-gadgetmanager-input-default' )
383 - .prop( 'checked', metadata.settings['default'] )
384 - .change( function() {
385 - metadata.settings['default'] = this.checked;
386 - });
387 -
388 - // Gadget settings: Hidden
389 - $form.find( '#mw-gadgetmanager-input-hidden' )
390 - .prop( 'checked', metadata.settings.hidden )
391 - .change( function() { metadata.settings.hidden = this.checked; });
392 -
393 - // Gadget settings: Shared
394 - $form.find( '#mw-gadgetmanager-input-shared' )
395 - .prop( 'checked', metadata.settings.shared )
396 - .change( function() { metadata.settings.shared = this.checked; });
397 -
398 -
399 - return $form;
400 - }
401 - };
402 -
403 - // Launch on document ready
404 - $( document ).ready( ga.ui.initUI );
405 -
406 -})( jQuery );
Index: branches/RL2/extensions/Gadgets/modules/ext.gadgets.gadgetmanager.prejs.css
@@ -1,14 +0,0 @@
2 -.mw-gadgetmanager-gadgets.mw-datatable th {
3 - padding: 2px 21px 2px 5px;
4 -}
5 -
6 -.mw-gadgetmanager-gadgets.mw-datatable td {
7 - padding: 2px 5px;
8 -}
9 -
10 -.mw-gadgetmanager-gadgets-default,
11 -.mw-gadgetmanager-gadgets-hidden,
12 -.mw-gadgetmanager-gadgets-shared {
13 - width: 4em;
14 - text-align: center;
15 -}
Index: branches/RL2/extensions/Gadgets/modules/ext.gadgets.prejs.css
@@ -0,0 +1,14 @@
 2+.mw-gadgetmanager-gadgets.mw-datatable th {
 3+ padding: 2px 21px 2px 5px;
 4+}
 5+
 6+.mw-gadgetmanager-gadgets.mw-datatable td {
 7+ padding: 2px 5px;
 8+}
 9+
 10+.mw-gadgetmanager-gadgets-default,
 11+.mw-gadgetmanager-gadgets-hidden,
 12+.mw-gadgetmanager-gadgets-shared {
 13+ width: 4em;
 14+ text-align: center;
 15+}
Property changes on: branches/RL2/extensions/Gadgets/modules/ext.gadgets.prejs.css
___________________________________________________________________
Added: svn:eol-style
116 + native
Index: branches/RL2/extensions/Gadgets/modules/ext.gadgets.gadgetmanager.css
@@ -0,0 +1,67 @@
 2+/**
 3+ * Styling for the gadget manager javascript-generated user interface.
 4+ */
 5+
 6+/**
 7+ * Form
 8+ */
 9+.mw-gadgetmanager-form fieldset {
 10+ margin: 0;
 11+}
 12+
 13+.mw-gadgetmanager-form table {
 14+ width: 100%;
 15+}
 16+
 17+.mw-gadgetmanager-form td,
 18+.mw-gadgetmanager-form th {
 19+ vertical-align: top;
 20+}
 21+
 22+/**
 23+ * The PropCloud
 24+ */
 25+.mw-gadgetmanager-propcloud {
 26+ background: white;
 27+ border: 1px solid grey;
 28+ overflow: hidden;
 29+}
 30+
 31+.mw-gadgetmanager-propcontainer {}
 32+
 33+.mw-gadgetmanager-prop {
 34+ float: left;
 35+ margin: 2px 5px 5px 2px;
 36+ padding: 2px 5px;
 37+ background: #e5eff6;
 38+ border: 1px solid #a4d2fb;
 39+ border-radius: 10px;
 40+ line-height: 1;
 41+}
 42+
 43+.mw-gadgetmanager-prop-label {}
 44+
 45+.mw-gadgetmanager-prop-delete {
 46+ display: inline-block;
 47+ width: 10px;
 48+ height: 10px;
 49+ /* @embed */
 50+ background: url(images/close.png) 50% 50% no-repeat;
 51+ opacity: 0.4;
 52+}
 53+
 54+.mw-gadgetmanager-prop:hover .mw-gadgetmanager-prop-delete {
 55+ opacity: 0.7;
 56+}
 57+
 58+.mw-gadgetmanager-prop:hover .mw-gadgetmanager-prop-delete:hover {
 59+ opacity: 1;
 60+ cursor: pointer;
 61+}
 62+
 63+.mw-gadgetmanager-propinput,
 64+.mw-gadgetmanager-propinput:focus {
 65+ border: 0;
 66+ outline: 0;
 67+ background: transparent;
 68+}
Index: branches/RL2/extensions/Gadgets/modules/ext.gadgets.gadgetmanager.js
@@ -0,0 +1,405 @@
 2+/**
 3+ * JavaScript to initialize the UI of the gadget manager.
 4+ *
 5+ * @author Timo Tijhof
 6+ * @copyright © 2011 Timo Tijhof
 7+ * @license GNU General Public Licence 2.0 or later
 8+ */
 9+( function( $ ) {
 10+
 11+ var
 12+ /**
 13+ * @var {Object} Local alias to mw.gadgets
 14+ */
 15+ ga = mw.gadgets,
 16+ /**
 17+ * @var {Object} HTML fragements
 18+ */
 19+ tpl = {
 20+ fancyForm: '<form class="mw-gadgetmanager-form">\
 21+ <fieldset>\
 22+ <legend>Module properties</legend>\
 23+ <table>\
 24+ <tr>\
 25+ <td><label for="mw-gadgetmanager-input-scripts"><html:msg key="gadgetmanager-prop-scripts"></label></td>\
 26+ <td><input type="text" id="mw-gadgetmanager-input-scripts" /></td>\
 27+ </tr>\
 28+ <tr>\
 29+ <td><label for="mw-gadgetmanager-input-styles"><html:msg key="gadgetmanager-prop-styles"></label></td>\
 30+ <td><input type="text" id="mw-gadgetmanager-input-styles" /></td>\
 31+ </tr>\
 32+ <tr>\
 33+ <td><label for="mw-gadgetmanager-input-dependencies"><html:msg key="gadgetmanager-prop-dependencies"></label></td>\
 34+ <td><input type="text" id="mw-gadgetmanager-input-dependencies" /></td>\
 35+ </tr>\
 36+ <tr>\
 37+ <td><label for="mw-gadgetmanager-input-messages"><html:msg key="gadgetmanager-prop-messages"></label></td>\
 38+ <td><input type="text" id="mw-gadgetmanager-input-messages" /></td>\
 39+ </tr>\
 40+ </table>\
 41+ </fieldset>\
 42+ <fieldset>\
 43+ <legend>Gadget settings</legend>\
 44+ <table>\
 45+ <tr>\
 46+ <td><label for="mw-gadgetmanager-input-category"><html:msg key="gadgetmanager-prop-category"></label></td>\
 47+ <td><select id="mw-gadgetmanager-input-category"></select></td>\
 48+ </tr>\
 49+ <tr>\
 50+ <td><label for="mw-gadgetmanager-input-rights"><html:msg key="gadgetmanager-prop-rights"></label></td>\
 51+ <td><input type="text" id="mw-gadgetmanager-input-rights" /></td>\
 52+ </tr>\
 53+ <tr>\
 54+ <td><label for="mw-gadgetmanager-input-default"><html:msg key="gadgetmanager-prop-default"></label></td>\
 55+ <td><input type="checkbox" id="mw-gadgetmanager-input-default" /></td>\
 56+ </tr>\
 57+ <tr>\
 58+ <td><label for="mw-gadgetmanager-input-hidden"><html:msg key="gadgetmanager-prop-hidden"></label></td>\
 59+ <td><input type="checkbox" id="mw-gadgetmanager-input-hidden" /></td>\
 60+ </tr>\
 61+ ' + ( ga.conf.enableSharing ? '<tr>\
 62+ <td><label for="mw-gadgetmanager-input-shared"><html:msg key="gadgetmanager-prop-shared"></label></td>\
 63+ <td><input type="checkbox" id="mw-gadgetmanager-input-shared" /></td>\
 64+ </tr>\
 65+ ' : '' ) + '</table>\
 66+ </fieldset>\
 67+ </form>'
 68+ },
 69+ /**
 70+ * @var {Object} Static cache for suggestions by script prefix.
 71+ */
 72+ suggestCacheScripts = {},
 73+ /**
 74+ * @var {Object} Static cache for suggestions by style prefix.
 75+ */
 76+ suggestCacheStyles = {},
 77+ /**
 78+ * @var {Object} Static cache for suggestions by messages prefix.
 79+ */
 80+ suggestCacheMsgs = {},
 81+ /**
 82+ * @var {Object} Complete static cache for module names. Lazy loaded from null.
 83+ */
 84+ suggestCacheDependencies = null,
 85+ /**
 86+ * @var {Object} Complete static cache for all rights.
 87+ */
 88+ suggestCacheRights = ga.conf.allRights,
 89+ /**
 90+ * @var {Number} Maximum number of autocomplete suggestions in the gadget editor input fields.
 91+ */
 92+ suggestLimit = 7;
 93+
 94+ /* Local functions */
 95+
 96+ /**
 97+ * Utility function to pad a zero
 98+ * to single digit number. Used by ISODateString().
 99+ * @param n {Number}
 100+ * @return {String}
 101+ */
 102+ function pad( n ) {
 103+ return n < 10 ? '0' + n : n;
 104+ }
 105+ /**
 106+ * Format a date in an ISO 8601 format using UTC.
 107+ * https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Date#Example:_ISO_8601_formatted_dates
 108+ *
 109+ * @param d {Date}
 110+ * @return {String}
 111+ */
 112+ function ISODateString( d ) {
 113+ return d.getUTCFullYear() + '-'
 114+ + pad( d.getUTCMonth() + 1 ) + '-'
 115+ + pad( d.getUTCDate() ) + 'T'
 116+ + pad( d.getUTCHours() ) + ':'
 117+ + pad( d.getUTCMinutes() ) + ':'
 118+ + pad( d.getUTCSeconds() ) + 'Z';
 119+ }
 120+
 121+ /* Public functions */
 122+
 123+ ga.ui = {
 124+ /**
 125+ * Initializes the the page. For now just binding click handlers
 126+ * to the anchor tags in the table.
 127+ */
 128+ initUI: function() {
 129+ // Bind trigger to the links
 130+ $( '.mw-gadgetmanager-gadgets .mw-gadgetmanager-gadgets-title a' )
 131+ .click( function( e ) {
 132+ e.preventDefault();
 133+ ga.ui.startGadgetEditor( $( this ).data( 'gadget-id' ) );
 134+ });
 135+ },
 136+
 137+ /**
 138+ * Initialize the gadget editor dialog.
 139+ *
 140+ * @asynchronous
 141+ * @param gadgetId {String}
 142+ */
 143+ startGadgetEditor: function( gadgetId ) {
 144+ // Ad hoc multi-loader. We need both requests, which are asynchronous,
 145+ // to be complete. Which ever finishes first will set the local variable
 146+ // to it's return value for the other callback to use.
 147+ // @todo Notification: In case of an 'error'.
 148+ var gadget, cats;
 149+
 150+ ga.api.getGadgetCategories( function( ret ) {
 151+ if ( gadget ) {
 152+ // getGadgetData already done
 153+ return ga.ui.showFancyForm( gadget, ret );
 154+ }
 155+ // getGadgetData not done yet, leave cats for it's callback to use
 156+ cats = ret;
 157+ });
 158+
 159+ ga.api.getGadgetData( gadgetId, function( ret ) {
 160+ if ( cats ) {
 161+ // getGadgetCategories already done
 162+ return ga.ui.showFancyForm( ret, cats );
 163+ }
 164+ // getGadgetCategories not done yet, leave gadget for it's callback to use
 165+ gadget = ret;
 166+ });
 167+ },
 168+
 169+ /**
 170+ * Generate form, create a dialog and open it into view.
 171+ *
 172+ * @param gadget {Object} Gadget object of the gadget to be modified.
 173+ * @param categories {Array} Gadget categories.
 174+ * @return {jQuery} The (dialogged) form.
 175+ */
 176+ showFancyForm: function( gadget, categories ) {
 177+ var $form = ga.ui.getFancyForm( gadget.metadata, categories ),
 178+ buttons = {};
 179+
 180+ // Form submit
 181+ buttons[mw.msg( 'gadgetmanager-editor-save' )] = function() {
 182+ ga.api.doModifyGadget( gadget, {
 183+ starttimestamp: ISODateString( new Date() ),
 184+ success: function( response ) {
 185+ $form.dialog( 'close' );
 186+ window.location.reload();
 187+ },
 188+ error: function( error ) {
 189+ mw.log( 'mw.gadgets.api.doModifyGadget: error', error );
 190+ // @todo Notification: $formNotif.add( .. );
 191+ }
 192+ });
 193+ };
 194+
 195+ return $form
 196+ .dialog({
 197+ autoOpen: true,
 198+ width: 800,
 199+ modal: true,
 200+ draggable: false,
 201+ resizable: false,
 202+ title: mw.message( 'gadgetmanager-editor-title', gadget.title ).escaped(),
 203+ buttons: buttons,
 204+ open: function() {
 205+ // Dialog is ready for action.
 206+ // Push out any notifications if some were queued up already between
 207+ // getting the gadget data and the display of the form.
 208+
 209+ // @todo Notification: $formNotif.add( .. );
 210+ }
 211+ });
 212+ },
 213+
 214+ /**
 215+ * Generate a <form> for the given module.
 216+ * Also binds events for submission and autocompletion.
 217+ *
 218+ * @param metadata {Object} Object to read and write to, used when saving
 219+ * the gadget metadata back through the API.
 220+ * @param categories {Array} Gadget categories.
 221+ * @return {jQuery} The form.
 222+ */
 223+ getFancyForm: function( metadata, categories ) {
 224+ var nsGadgetId = mw.config.get( 'wgNamespaceIds' ).gadget,
 225+ $form = $( tpl.fancyForm ).localize();
 226+
 227+ // Module properties: scripts
 228+ $form.find( '#mw-gadgetmanager-input-scripts' ).createPropCloud({
 229+ props: metadata.module.scripts,
 230+ autocompleteSource: function( data, response ) {
 231+ // Use cache if available
 232+ if ( data.term in suggestCacheScripts ) {
 233+ response( suggestCacheScripts[data.term] );
 234+ return;
 235+ }
 236+ $.getJSON( mw.util.wikiScript( 'api' ), {
 237+ format: 'json',
 238+ action: 'query',
 239+ list: 'gadgetpages',
 240+ gpnamespace: nsGadgetId,
 241+ gpextension: 'js',
 242+ gpprefix: data.term
 243+ }, function( json ) {
 244+ if ( json && json.query && json.query.gadgetpages ) {
 245+ var suggestions = json.query.gadgetpages.splice( 0, suggestLimit );
 246+ suggestions = $.map( suggestions, function( val, i ) {
 247+ return val.pagename;
 248+ });
 249+
 250+ // Update cache
 251+ suggestCacheScripts[data.term] = suggestions;
 252+
 253+ response( suggestions );
 254+ } else {
 255+ response( [] );
 256+ }
 257+ }
 258+ );
 259+ },
 260+ prefix: 'mw-gadgetmanager-',
 261+ removeTooltip: mw.msg( 'gadgetmanager-editor-removeprop-tooltip' )
 262+ });
 263+
 264+ // Module properties: styles
 265+ $form.find( '#mw-gadgetmanager-input-styles' ).createPropCloud({
 266+ props: metadata.module.styles,
 267+ autocompleteSource: function( data, response ) {
 268+ // Use cache if available
 269+ if ( data.term in suggestCacheStyles ) {
 270+ response( suggestCacheStyles[data.term] );
 271+ return;
 272+ }
 273+ $.getJSON( mw.util.wikiScript( 'api' ), {
 274+ format: 'json',
 275+ action: 'query',
 276+ list: 'gadgetpages',
 277+ gpnamespace: nsGadgetId,
 278+ gpextension: 'css',
 279+ gpprefix: data.term
 280+ }, function( json ) {
 281+ if ( json && json.query && json.query.gadgetpages ) {
 282+ var suggestions = $.map( json.query.gadgetpages, function( val, i ) {
 283+ return val.pagename;
 284+ });
 285+ suggestions = suggestions.splice( 0, suggestLimit );
 286+
 287+ // Update cache
 288+ suggestCacheStyles[data.term] = suggestions;
 289+
 290+ response( suggestions );
 291+ } else {
 292+ response( [] );
 293+ }
 294+ }
 295+ );
 296+ },
 297+ prefix: 'mw-gadgetmanager-',
 298+ removeTooltip: mw.msg( 'gadgetmanager-editor-removeprop-tooltip' )
 299+ });
 300+
 301+ // Module properties: dependencies
 302+ $form.find( '#mw-gadgetmanager-input-dependencies' ).createPropCloud({
 303+ props: metadata.module.dependencies,
 304+ autocompleteSource: function( data, response ) {
 305+ if ( suggestCacheDependencies === null ) {
 306+ suggestCacheDependencies = mw.loader.getModuleNames();
 307+ }
 308+ var output = $.ui.autocomplete.filter( suggestCacheDependencies, data.term );
 309+ response( output.slice( 0, suggestLimit ) );
 310+ },
 311+ prefix: 'mw-gadgetmanager-',
 312+ removeTooltip: mw.msg( 'gadgetmanager-editor-removeprop-tooltip' )
 313+ });
 314+
 315+ // Module properties: messages
 316+ $form.find( '#mw-gadgetmanager-input-messages' ).createPropCloud({
 317+ props: metadata.module.messages,
 318+ autocompleteSource: function( data, response ) {
 319+ // Use cache if available
 320+ if ( data.term in suggestCacheMsgs ) {
 321+ response( suggestCacheMsgs[data.term] );
 322+ return;
 323+ }
 324+ $.getJSON( mw.util.wikiScript( 'api' ), {
 325+ format: 'json',
 326+ action: 'query',
 327+ meta: 'allmessages',
 328+ amprefix: data.term,
 329+ amnocontent: true,
 330+ amlang: mw.config.get( 'wgContentLanguage' )
 331+ }, function( json ) {
 332+ if ( json && json.query && json.query.allmessages ) {
 333+ var suggestions = $.map( json.query.allmessages, function( val, i ) {
 334+ return val.name;
 335+ });
 336+ suggestions = suggestions.splice( 0, suggestLimit );
 337+
 338+ // Update cache
 339+ suggestCacheMsgs[data.term] = suggestions;
 340+
 341+ response( suggestions );
 342+ } else {
 343+ response( [] );
 344+ }
 345+ }
 346+ );
 347+ },
 348+ prefix: 'mw-gadgetmanager-',
 349+ removeTooltip: mw.msg( 'gadgetmanager-editor-removeprop-tooltip' )
 350+ });
 351+
 352+ // Gadget settings: category
 353+ $form.find( '#mw-gadgetmanager-input-category' ).append( function() {
 354+ var current = metadata.settings.category,
 355+ opts = '',
 356+ i = 0,
 357+ cat;
 358+ for ( ; i < categories.length; i++ ) {
 359+ cat = categories[i];
 360+ opts += mw.html.element( 'option', {
 361+ value: cat.name,
 362+ selected: cat.name === current
 363+ }, cat.title );
 364+ }
 365+ return opts;
 366+ }).change( function() {
 367+ metadata.settings.category = $(this).val();
 368+ });
 369+
 370+ // Gadget settings: rights
 371+ $form.find( '#mw-gadgetmanager-input-rights' ).createPropCloud({
 372+ props: metadata.settings.rights,
 373+ autocompleteSource: function( data, response ) {
 374+ var output = $.ui.autocomplete.filter( suggestCacheRights, data.term );
 375+ response( output.slice( 0, suggestLimit ) );
 376+ },
 377+ prefix: 'mw-gadgetmanager-',
 378+ removeTooltip: mw.msg( 'gadgetmanager-editor-removeprop-tooltip' )
 379+ });
 380+
 381+ // Gadget settings: Default
 382+ $form.find( '#mw-gadgetmanager-input-default' )
 383+ .prop( 'checked', metadata.settings['default'] )
 384+ .change( function() {
 385+ metadata.settings['default'] = this.checked;
 386+ });
 387+
 388+ // Gadget settings: Hidden
 389+ $form.find( '#mw-gadgetmanager-input-hidden' )
 390+ .prop( 'checked', metadata.settings.hidden )
 391+ .change( function() { metadata.settings.hidden = this.checked; });
 392+
 393+ // Gadget settings: Shared
 394+ $form.find( '#mw-gadgetmanager-input-shared' )
 395+ .prop( 'checked', metadata.settings.shared )
 396+ .change( function() { metadata.settings.shared = this.checked; });
 397+
 398+
 399+ return $form;
 400+ }
 401+ };
 402+
 403+ // Launch on document ready
 404+ $( document ).ready( ga.ui.initUI );
 405+
 406+})( jQuery );

Follow-up revisions

RevisionCommit summaryAuthorDate
r97570[RL2] Commit old SpecialGadgets.php...krinkle22:52, 19 September 2011
r98854Fix various typos in r97513 and r98729catrope10:31, 4 October 2011

Past revisions this follows-up on

RevisionCommit summaryAuthorDate
r96309[ResourceLoader2] Gadget manager (start of ajax editor)...krinkle22:28, 5 September 2011

Comments

#Comment by Krinkle (talk | contribs)   16:52, 19 September 2011

Yeah, heavily broken. Work-in-progress. Broken up into pieces to keep working copy sane with deletions, moves and additions.

#Comment by Catrope (talk | contribs)   10:31, 4 October 2011

gadgets-pagetext weirdness was cleaned up in r98729.

Status & tagging log