Index: trunk/extensions/ApiSandbox/SpecialApiSandbox.php |
— | — | @@ -0,0 +1,81 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +class SpecialApiSandbox extends SpecialPage { |
| 5 | + |
| 6 | + /** |
| 7 | + * Constructor |
| 8 | + */ |
| 9 | + public function __construct() { |
| 10 | + parent::__construct( 'ApiSandbox', '', true ); |
| 11 | + } |
| 12 | + |
| 13 | + /** |
| 14 | + * Main execution function |
| 15 | + * @param $par Parameters passed to the page |
| 16 | + */ |
| 17 | + public function execute( $par ) { |
| 18 | + global $wgEnableAPI; |
| 19 | + |
| 20 | + $out = $this->getContext()->getOutput(); |
| 21 | + |
| 22 | + if ( !$wgEnableAPI ) { |
| 23 | + $out->showErrorPage( 'error', 'apisb-api-disabled' ); |
| 24 | + } |
| 25 | + |
| 26 | + $this->setHeaders(); |
| 27 | + $out->setPageTitle( wfMessage( 'apisb-title' )->parse() ); |
| 28 | + $out->addModules( 'ext.apiSandbox' ); |
| 29 | + |
| 30 | + $out->addHTML( '<noscript>' . wfMessage( 'apisb-no-js' )->escaped() . '</noscript> |
| 31 | +<div id="api-sandbox-content" style="display: none">' ); |
| 32 | + $out->addWikiMsg( 'apisb-intro' ); |
| 33 | + $out->addHTML( $this->openFieldset( 'parameters' ) |
| 34 | + . $this->getInputs() . ' |
| 35 | +</fieldset> |
| 36 | +' . $this->openFieldset( 'result' ) . ' |
| 37 | +</fieldset>' ); |
| 38 | + |
| 39 | + $out->addHTML( '</div>' ); # <div id="api-sandbox-content"> |
| 40 | + } |
| 41 | + |
| 42 | + private function getInputs() { |
| 43 | + global $wgEnableWriteAPI; |
| 44 | + |
| 45 | + $apiMain = new ApiMain( new FauxRequest( array() ), $wgEnableWriteAPI ); |
| 46 | + $apiQuery = new ApiQuery( $apiMain, 'query' ); |
| 47 | + |
| 48 | + $s = '<table class="api-sandbox-options"> |
| 49 | +<tbody> |
| 50 | +<tr><td class="api-sandbox-label"><label for="api-sandbox-action">action=</label></td><td class="api-sandbox-value">' |
| 51 | + . $this->getSelect( 'action', $apiMain->getModules() ) . '</td><td id="api-sandbox-help" rowspan="2"></td></tr> |
| 52 | +'; |
| 53 | + $s .= '<tr id="api-sandbox-prop-row" style="display: none"><td class="api-sandbox-label"><label for="api-sandbox-prop">prop=</label></td><td class="api-sandbox-value">' |
| 54 | + . $this->getSelect( 'prop', $apiQuery->getModules() ) |
| 55 | + . '</td></tr> |
| 56 | +</table> |
| 57 | +<div id="api-sandbox-further-inputs"></div> |
| 58 | +'; |
| 59 | + return $s; |
| 60 | + } |
| 61 | + |
| 62 | + private function getSelect( $name, $items ) { |
| 63 | + $items = array_keys( $items ); |
| 64 | + sort( $items ); |
| 65 | + $s = Html::openElement( 'select', array( 'class' => 'api-sandbox-input', 'name' => $name, 'id' => "api-sandbox-$name" ) ); |
| 66 | + $s .= "\n\t" . Html::element( 'option', |
| 67 | + array( 'value' => '-', 'selected' => 'selected' ), |
| 68 | + wfMessage( "apisb-select-$name" )->text() |
| 69 | + ); |
| 70 | + foreach ( $items as $item ) { |
| 71 | + $s .= "\n\t" . Html::element( 'option', array( 'value' => $item ), $item ); |
| 72 | + } |
| 73 | + $s .= "\n" . Html::closeElement( 'select' ) . "\n"; |
| 74 | + return $s; |
| 75 | + } |
| 76 | + |
| 77 | + private function openFieldset( $name ) { |
| 78 | + return "\n" . Html::openElement( 'fieldset', array( 'id' => "api-sandbox-$name" ) ) |
| 79 | + . "\n\t" . Html::rawElement( 'legend', array(), wfMessage( "apisb-$name" )->parse() ) |
| 80 | + . "\n"; |
| 81 | + } |
| 82 | +} |
\ No newline at end of file |
Property changes on: trunk/extensions/ApiSandbox/SpecialApiSandbox.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 83 | + native |
Index: trunk/extensions/ApiSandbox/ext.apiSandbox.js |
— | — | @@ -0,0 +1,174 @@ |
| 2 | +$( document ).ready( function() { |
| 3 | + var content = $( '#api-sandbox-content' ); |
| 4 | + if ( !content.length ) { |
| 5 | + return; |
| 6 | + } |
| 7 | + content.show(); |
| 8 | + |
| 9 | + var action = $( '#api-sandbox-action' ); |
| 10 | + var prop = $( '#api-sandbox-prop' ); |
| 11 | + var propRow = $( '#api-sandbox-prop-row' ); |
| 12 | + var help = $( '#api-sandbox-help' ); |
| 13 | + var further = $( '#api-sandbox-further-inputs' ); |
| 14 | + var actionCache = []; |
| 15 | + var propCache = []; |
| 16 | + |
| 17 | + function isset( x ) { |
| 18 | + return typeof x != 'undefined'; |
| 19 | + } |
| 20 | + |
| 21 | + function showLoading( element ) { |
| 22 | + element.html( mw.msg( 'apisb-loading' ) ); // @todo: |
| 23 | + } |
| 24 | + |
| 25 | + function showLoadError( element ) { |
| 26 | + element.html( '<span style="error">' + mw.msg( 'apisb-load-error' ) + '</span>' ); |
| 27 | + } |
| 28 | + |
| 29 | + function parseParamInfo( data ) { |
| 30 | + further.text( '' ); |
| 31 | + if ( !isset( data.paraminfo ) |
| 32 | + || ( !isset( data.paraminfo.modules ) && !isset( data.paraminfo.querymodules ) ) |
| 33 | + ) |
| 34 | + { |
| 35 | + showLoadError( further ); |
| 36 | + return; |
| 37 | + } |
| 38 | + if ( isset( data.paraminfo.modules ) ) { |
| 39 | + actionCache[data.paraminfo.modules[0].name] = data.paraminfo.modules[0]; |
| 40 | + createInputs( actionCache[data.paraminfo.modules[0].name] ); |
| 41 | + } else { |
| 42 | + propCache[data.paraminfo.querymodules[0].name] = data.paraminfo.querymodules[0]; |
| 43 | + createInputs( propCache[data.paraminfo.querymodules[0].name] ); |
| 44 | + } |
| 45 | + |
| 46 | + } |
| 47 | + |
| 48 | + function getQueryInfo( action, prop ) { |
| 49 | + var isQuery = action == 'query'; |
| 50 | + if ( action == '-' || ( isQuery && prop == '-' ) ) { |
| 51 | + return; |
| 52 | + } |
| 53 | + var cached; |
| 54 | + if ( isQuery ) { |
| 55 | + cached = propCache[prop]; |
| 56 | + } else { |
| 57 | + cached = actionCache[action]; |
| 58 | + } |
| 59 | + if ( typeof cached != 'object' ) { // stupid FF adds watch() everywhere |
| 60 | + showLoading( further ); |
| 61 | + var data = { |
| 62 | + format: 'json', |
| 63 | + action: 'paraminfo', |
| 64 | + }; |
| 65 | + if (isQuery ) { |
| 66 | + data.querymodules = prop; |
| 67 | + } else { |
| 68 | + data.modules = action; |
| 69 | + } |
| 70 | + $.getJSON( |
| 71 | + mw.config.get( 'wgScriptPath' ) + '/api' + mw.config.get( 'wgScriptExtension' ), |
| 72 | + data, |
| 73 | + parseParamInfo |
| 74 | + ); |
| 75 | + } else { |
| 76 | + createInputs( cached ); |
| 77 | + } |
| 78 | + } |
| 79 | + |
| 80 | + function createInputs( info ) { |
| 81 | + help.text( info.description ); |
| 82 | + var s = '<table class="api-sandbox-options">\n<tbody>'; |
| 83 | + for ( var i = 0; i < info.parameters.length; i++ ) { |
| 84 | + var param = info.parameters[i]; |
| 85 | + var name = info.prefix + param.name; |
| 86 | + var desc = mw.html.escape( param.description ); |
| 87 | + if ( desc.indexOf( '\n ' ) >= 0 ) { |
| 88 | + desc = desc.replace( /^(.*?)((?:\n\s+[^\n]*)+)(.*?)$/m, '$1<ul>$2</ul>$3' ); |
| 89 | + desc = desc.replace( /\n\s+([^\n]*)/g, '\n<li>$1</li>' ); |
| 90 | + } |
| 91 | + desc = desc.replace( /\n(?!<)/, '\n<br/>' ); |
| 92 | + |
| 93 | + s += '<tr><td class="api-sandbox-label"><label for="param-' + name + '">' + name + '=</label></td>' |
| 94 | + + '<td class="api-sandbox-value">' + input( param, name ) |
| 95 | + + '</td><td>' + desc + '</td></tr>'; |
| 96 | + } |
| 97 | + s += '\n</tbody>\n</table>\n'; |
| 98 | + further.html( s ); |
| 99 | + } |
| 100 | + |
| 101 | + function input( param, name ) { |
| 102 | + var s = param.type; |
| 103 | + var value = ''; |
| 104 | + switch ( param.type ) { |
| 105 | + case 'limit': |
| 106 | + value = 10; |
| 107 | + case 'integer': |
| 108 | + case 'string': |
| 109 | + case 'user': |
| 110 | + s = '<input class="api-sandbox-input" id="param-' + name + '" value="' + value + '"/>'; |
| 111 | + break; |
| 112 | + case 'bool': |
| 113 | + case 'boolean': |
| 114 | + s = '<input id="param-' + name + '" type="checkbox"/>'; |
| 115 | + break; |
| 116 | + default: |
| 117 | + if ( typeof param.type == 'object' ) { |
| 118 | + var id = 'param-' + name; |
| 119 | + var attributes = { 'id': id }; |
| 120 | + if ( isset( param.multi ) ) { |
| 121 | + attributes.multiple = 'multiple'; |
| 122 | + s = select( param.type, attributes, false ); |
| 123 | + } else { |
| 124 | + s = select( param.type, attributes, true ); |
| 125 | + } |
| 126 | + } |
| 127 | + } |
| 128 | + return s; |
| 129 | + } |
| 130 | + |
| 131 | + function select( values, attributes, selected ) { |
| 132 | + var s = '<select class="api-sandbox-input"'; |
| 133 | + if ( isset( attributes.multiple ) ) { |
| 134 | + s += ' size="' + values.length + '"'; |
| 135 | + } |
| 136 | + for ( var a in attributes ) { |
| 137 | + s += ' ' + a + '="' + attributes[a] + '"'; |
| 138 | + } |
| 139 | + s += '>'; |
| 140 | + if ( typeof selected != 'array' ) { |
| 141 | + if ( selected ) { |
| 142 | + s += '\n<option value="" selected="selected">' + mw.msg( 'apisb-select-value' ) + '</option>'; |
| 143 | + } |
| 144 | + selected = []; |
| 145 | + } |
| 146 | + for ( var i = 0; i < values.length; i++ ) { |
| 147 | + s += '\n<option value="' + values[i] + '"'; |
| 148 | + if ( $.inArray( values[i], selected ) >= 0 ) { |
| 149 | + s += ' selected="selected"'; |
| 150 | + } |
| 151 | + s += '>' + values[i] + '</option>'; |
| 152 | + } |
| 153 | + s += '\n</select>'; |
| 154 | + return s; |
| 155 | + } |
| 156 | + |
| 157 | + function updateBasics() { |
| 158 | + var a = action.val(); |
| 159 | + var p = prop.val(); |
| 160 | + var isQuery = a == 'query'; |
| 161 | + if ( isQuery ) { |
| 162 | + propRow.show(); |
| 163 | + } else { |
| 164 | + propRow.hide(); |
| 165 | + } |
| 166 | + further.text( '' ); |
| 167 | + help.text( '' ); |
| 168 | + getQueryInfo( a, p ); |
| 169 | + } |
| 170 | + |
| 171 | + action.change( updateBasics ); |
| 172 | + prop.change( updateBasics ); |
| 173 | + |
| 174 | + |
| 175 | +}); |
\ No newline at end of file |
Property changes on: trunk/extensions/ApiSandbox/ext.apiSandbox.js |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 176 | + native |
Index: trunk/extensions/ApiSandbox/ApiSandbox.alias.php |
— | — | @@ -0,0 +1,18 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Aliases for Special:ApiSandbox |
| 5 | + * |
| 6 | + * @file |
| 7 | + * @ingroup Extensions |
| 8 | + */ |
| 9 | + |
| 10 | +$specialPageAliases = array(); |
| 11 | + |
| 12 | +/** |
| 13 | + * English |
| 14 | + */ |
| 15 | +$specialPageAliases['en'] = array( |
| 16 | + 'ApiSandbox' => array( 'ApiSandbox' ), |
| 17 | +); |
| 18 | + |
| 19 | +$aliases =& $specialPageAliases; |
Property changes on: trunk/extensions/ApiSandbox/ApiSandbox.alias.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 20 | + native |
Index: trunk/extensions/ApiSandbox/ApiSandbox.i18n.php |
— | — | @@ -0,0 +1,18 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +$messages = array(); |
| 5 | + |
| 6 | +$messages['en'] = array( |
| 7 | + 'apisb-desc' => 'Allows to debug [http://www.mediawiki.org/wiki/API MediaWiki API] calls from browser', |
| 8 | + 'apisb-title' => 'API sandbox', |
| 9 | + 'apisb-no-js' => "'''Error''': this feature requires JavaScript.", |
| 10 | + 'apisb-intro' => 'Blah blah intro, dude!', |
| 11 | + 'apisb-api-disabled' => 'API is disabled on this site.', |
| 12 | + 'apisb-parameters' => 'Parameters', |
| 13 | + 'apisb-result' => 'Result', |
| 14 | + 'apisb-select-action' => 'Select action', |
| 15 | + 'apisb-select-prop' => 'Select property', |
| 16 | + 'apisb-select-value' => 'Select value', |
| 17 | + 'apisb-loading' => 'Loading...', |
| 18 | + 'apisb-load-error' => 'Error loading API description', |
| 19 | +); |
\ No newline at end of file |
Property changes on: trunk/extensions/ApiSandbox/ApiSandbox.i18n.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 20 | + native |
Index: trunk/extensions/ApiSandbox/ApiSandbox.php |
— | — | @@ -0,0 +1,33 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * API sandbox extension. Initial author Max Semenik, based on idea by Salil P. A. |
| 5 | + * License: WTFPL 2.0 |
| 6 | + */ |
| 7 | + |
| 8 | + |
| 9 | +$wgExtensionCredits['other'][] = array( |
| 10 | + 'path' => __FILE__, |
| 11 | + 'name' => 'ApiSandbox', |
| 12 | + 'author' => array( 'Max Semenik' ), |
| 13 | + 'url' => 'http://mediawiki.org/wiki/Extension:ApiSandbox', |
| 14 | + 'descriptionmsg' => 'apisb-desc', |
| 15 | +); |
| 16 | + |
| 17 | +$dir = dirname(__FILE__) . '/'; |
| 18 | + |
| 19 | +$wgExtensionMessagesFiles['ApiSandbox'] = $dir . 'ApiSandbox.i18n.php'; |
| 20 | +$wgExtensionAliasesFiles['ApiSandbox'] = $dir . 'ApiSandbox.alias.php'; |
| 21 | + |
| 22 | +$wgAutoloadClasses['SpecialApiSandbox'] = $dir . 'SpecialApiSandbox.php'; |
| 23 | + |
| 24 | +$wgSpecialPages['ApiSandbox'] = 'SpecialApiSandbox'; |
| 25 | +$wgSpecialPageGroups['Gadgets'] = 'wiki'; |
| 26 | + |
| 27 | +$wgResourceModules['ext.apiSandbox'] = array( |
| 28 | + 'scripts' => 'ext.apiSandbox.js', |
| 29 | + 'styles' => 'ext.apiSandbox.css', |
| 30 | + 'dependencies' => array( 'jquery.json' ), |
| 31 | + 'localBasePath' => dirname( __FILE__ ), |
| 32 | + 'remoteExtPath' => 'ApiSandbox', |
| 33 | + 'messages' => array( 'apisb-loading', 'apisb-load-error', 'apisb-select-value' ), |
| 34 | +); |
Property changes on: trunk/extensions/ApiSandbox/ApiSandbox.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 35 | + native |
Index: trunk/extensions/ApiSandbox/ext.apiSandbox.css |
— | — | @@ -0,0 +1,20 @@ |
| 2 | +table.api-sandbox-options { |
| 3 | + width: 100%; |
| 4 | +} |
| 5 | + |
| 6 | +td.api-sandbox-label { |
| 7 | + text-align: right; |
| 8 | + width: 12em; |
| 9 | + vertical-align: top; |
| 10 | + font-family: monospace; |
| 11 | +} |
| 12 | + |
| 13 | +td.api-sandbox-value { |
| 14 | + width: 18em; |
| 15 | + vertical-align: top; |
| 16 | + overflow: auto; |
| 17 | +} |
| 18 | + |
| 19 | +.api-sandbox-input { |
| 20 | + width: 17em; |
| 21 | +} |
\ No newline at end of file |
Property changes on: trunk/extensions/ApiSandbox/ext.apiSandbox.css |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 22 | + native |