From fe1e817d2af5593a54b5576dbf0005ca1e97c418 Mon Sep 17 00:00:00 2001 From: Brad Jorsch Date: Sun, 22 Jan 2017 13:44:58 -0500 Subject: [PATCH] ApiSandbox: Allow displaying query parameters in various formats I9c24a230 added a box with a JSON-formatted version of the request parmeters, saying "In the future we can provide more formats via a dropdown". That future should have been then. It is now. Beyond simply making it possible to select the format via a dropdown, this change adds a JS hook, apisandbox.formatRequest, to allow adding new formats from extensions, gadgets, and site scripts instead of requiring them all to be added to core. Change-Id: I20b093e0891f36cb3f1faa3eb3d6aed0f17b6b7d --- languages/i18n/en.json | 4 + languages/i18n/qqq.json | 6 +- resources/Resources.php | 4 + .../mediawiki.special.apisandbox.css | 8 ++ .../mediawiki.special.apisandbox.js | 98 ++++++++++++++++++- 5 files changed, 114 insertions(+), 6 deletions(-) diff --git a/languages/i18n/en.json b/languages/i18n/en.json index f2ff14baa6..a149b4ab7b 100644 --- a/languages/i18n/en.json +++ b/languages/i18n/en.json @@ -1960,7 +1960,11 @@ "apisandbox-sending-request": "Sending API request...", "apisandbox-loading-results": "Receiving API results...", "apisandbox-results-error": "An error occurred while loading the API query response: $1.", + "apisandbox-request-selectformat-label": "Show request data as:", + "apisandbox-request-format-url-label": "URL query string", "apisandbox-request-url-label": "Request URL:", + "apisandbox-request-format-json-label": "JSON", + "apisandbox-request-json-label": "Request JSON:", "apisandbox-request-time": "Request time: {{PLURAL:$1|$1 ms}}", "apisandbox-results-fixtoken": "Correct token and resubmit", "apisandbox-results-fixtoken-fail": "Failed to fetch \"$1\" token.", diff --git a/languages/i18n/qqq.json b/languages/i18n/qqq.json index 1e71b88201..20e80b6711 100644 --- a/languages/i18n/qqq.json +++ b/languages/i18n/qqq.json @@ -2146,7 +2146,11 @@ "apisandbox-sending-request": "JavaScript message displayed while the request is being sent.", "apisandbox-loading-results": "JavaScript message displayed while the response is being read.", "apisandbox-results-error": "Displayed as an error message from JavaScript when the request failed.\n\nParameters:\n* $1 - Error message", - "apisandbox-request-url-label": "Label for the text field displaying the URL used to make this request.", + "apisandbox-request-selectformat-label": "Label for the format selector on the results page.", + "apisandbox-request-format-url-label": "Label for the menu item to select URL format.\n\nSee also:\n* {{msg-mw|apisandbox-request-selectformat-label}}\n* {{msg-mw|apisandbox-request-url-label}}", + "apisandbox-request-url-label": "Label for the text field displaying the URL used to make this request.\n\nSee also:\n* {{msg-mw|apisandbox-request-format-url-label}}", + "apisandbox-request-format-json-label": "Label for the menu item to select JSON format.\n\nSee also:\n* {{msg-mw|apisandbox-request-selectformat-label}}\n* {{msg-mw|apisandbox-request-json-label}}", + "apisandbox-request-json-label": "Label for text field display the request parameters as JSON.\n\nSee also:\n* {{msg-mw|apisandbox-request-format-json-label}}", "apisandbox-request-time": "Label and value for displaying the time taken by the request.\n\nParameters:\n* $1 - Time taken in milliseconds", "apisandbox-results-fixtoken": "JavaScript button label", "apisandbox-results-fixtoken-fail": "Displayed as an error message from JavaScript when a CSRF token could not be fetched.\n\nParameters:\n* $1 - Token type", diff --git a/resources/Resources.php b/resources/Resources.php index bd7f68e055..2c3c46e14e 100644 --- a/resources/Resources.php +++ b/resources/Resources.php @@ -1853,7 +1853,11 @@ return [ 'apisandbox-sending-request', 'apisandbox-loading-results', 'apisandbox-results-error', + 'apisandbox-request-selectformat-label', + 'apisandbox-request-format-url-label', 'apisandbox-request-url-label', + 'apisandbox-request-format-json-label', + 'apisandbox-request-json-label', 'apisandbox-request-time', 'apisandbox-results-fixtoken', 'apisandbox-results-fixtoken-fail', diff --git a/resources/src/mediawiki.special/mediawiki.special.apisandbox.css b/resources/src/mediawiki.special/mediawiki.special.apisandbox.css index 99f6c132a2..59a03f3117 100644 --- a/resources/src/mediawiki.special/mediawiki.special.apisandbox.css +++ b/resources/src/mediawiki.special/mediawiki.special.apisandbox.css @@ -85,3 +85,11 @@ .oo-ui-textInputWidget.oo-ui-widget-enabled > .oo-ui-indicatorElement-indicator.mw-apisandbox-clickable-indicator { cursor: pointer; } + +.mw-apisandbox-textInputCode .oo-ui-inputWidget-input { + font-family: monospace, monospace; + font-size: 0.8125em; + -moz-tab-size: 4; + -o-tab-size: 4; + tab-size: 4; +} diff --git a/resources/src/mediawiki.special/mediawiki.special.apisandbox.js b/resources/src/mediawiki.special/mediawiki.special.apisandbox.js index e9922f81e8..ad58583884 100644 --- a/resources/src/mediawiki.special/mediawiki.special.apisandbox.js +++ b/resources/src/mediawiki.special/mediawiki.special.apisandbox.js @@ -3,6 +3,7 @@ 'use strict'; var ApiSandbox, Util, WidgetMethods, Validators, $content, panel, booklet, oldhash, windowManager, fullscreenButton, + formatDropdown, api = new mw.Api(), bookletPages = [], availableFormats = {}, @@ -626,6 +627,70 @@ .filter( '[href]:not([target])' ) .attr( 'target', '_blank' ); return $html; + }, + + /** + * Format a request and return a bunch of menu option widgets + * + * @param {Object} displayParams Query parameters, sanitized for display. + * @param {Object} rawParams Query parameters. You should probably use displayParams instead. + * @return {OO.ui.MenuOptionWidget[]} Each item's data should be an OO.ui.FieldLayout + */ + formatRequest: function ( displayParams, rawParams ) { + var jsonInput, + items = [ + new OO.ui.MenuOptionWidget( { + label: Util.parseMsg( 'apisandbox-request-format-url-label' ), + data: new OO.ui.FieldLayout( + new OO.ui.TextInputWidget( { + readOnly: true, + value: mw.util.wikiScript( 'api' ) + '?' + $.param( displayParams ) + } ), { + label: Util.parseMsg( 'apisandbox-request-url-label' ) + } + ) + } ), + new OO.ui.MenuOptionWidget( { + label: Util.parseMsg( 'apisandbox-request-format-json-label' ), + data: new OO.ui.FieldLayout( + jsonInput = new OO.ui.TextInputWidget( { + classes: [ 'mw-apisandbox-textInputCode' ], + readOnly: true, + multiline: true, + autosize: true, + maxRows: 6, + value: JSON.stringify( displayParams, null, '\t' ) + } ), { + label: Util.parseMsg( 'apisandbox-request-json-label' ) + } + ).on( 'toggle', function ( visible ) { + if ( visible ) { + // Call updatePosition instead of adjustSize + // because the latter has weird caching + // behavior and the former bypasses it. + jsonInput.updatePosition(); + } + } ) + } ) + ]; + + mw.hook( 'apisandbox.formatRequest' ).fire( items, displayParams, rawParams ); + + return items; + }, + + /** + * Event handler for when formatDropdown's selection changes + */ + onFormatDropdownChange: function () { + var i, + menu = formatDropdown.getMenu(), + items = menu.getItems(), + selectedField = menu.getSelectedItem() ? menu.getSelectedItem().getData() : null; + + for ( i = 0; i < items.length; i++ ) { + items[ i ].getData().toggle( items[ i ].getData() === selectedField ); + } } }; @@ -918,6 +983,8 @@ } $.when.apply( $, deferreds ).done( function () { + var formatItems, menu, selectedLabel; + if ( $.inArray( false, arguments ) !== -1 ) { windowManager.openWindow( 'errorAlert', { title: Util.parseMsg( 'apisandbox-submit-invalid-fields-title' ), @@ -935,6 +1002,8 @@ query = $.param( displayParams ); + formatItems = Util.formatRequest( displayParams, params ); + // Force a 'fm' format with wrappedhtml=1, if available if ( params.format !== undefined ) { if ( availableFormats.hasOwnProperty( params.format + 'fm' ) ) { @@ -959,16 +1028,35 @@ page.setupOutlineItem = function () { this.outlineItem.setLabel( mw.message( 'apisandbox-results' ).text() ); }; + + if ( !formatDropdown ) { + formatDropdown = new OO.ui.DropdownWidget( { + menu: { items: [] } + } ); + formatDropdown.getMenu().on( 'choose', Util.onFormatDropdownChange ); + } + + menu = formatDropdown.getMenu(); + selectedLabel = menu.getSelectedItem() ? menu.getSelectedItem().getLabel() : ''; + if ( typeof selectedLabel !== 'string' ) { + selectedLabel = selectedLabel.text(); + } + menu.clearItems().addItems( formatItems ); + menu.chooseItem( menu.getItemFromLabel( selectedLabel ) || menu.getFirstSelectableItem() ); + + // Fire the event to update field visibilities + Util.onFormatDropdownChange(); + page.$element.empty() .append( new OO.ui.FieldLayout( - new OO.ui.TextInputWidget( { - readOnly: true, - value: mw.util.wikiScript( 'api' ) + '?' + query - } ), { - label: Util.parseMsg( 'apisandbox-request-url-label' ) + formatDropdown, { + label: Util.parseMsg( 'apisandbox-request-selectformat-label' ) } ).$element, + $.map( formatItems, function ( item ) { + return item.getData().$element; + } ), $result ); ApiSandbox.updateUI(); -- 2.20.1