Jump to content

User:PleaseStand/userScriptSandbox-dev.js

From Wikipedia, the free encyclopedia
This is an old revision of this page, as edited by PleaseStand (talk | contribs) at 01:11, 7 October 2017 (actually show the enable switch). The present address (URL) is a permanent link to this revision, which may differ significantly from the current revision.
Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.
/*!
 * User script sandbox
 * http://en.wikipedia.org/wiki/Wikipedia:User_script_sandbox
 *
 * Copyright 2012 Wikipedia user PleaseStand
 *
 * Licensed under the Creative Commons Attribution-Share-Alike 3.0 Unported License,
 * the GNU Free Documentation License (unversioned), and the GNU General Public License
 * (version 2 or any later version); pick the license(s) of your choice.
 *
 
 * http://www.gnu.org/copyleft/fdl.html
 * http://www.gnu.org/copyleft/gpl.html
 */

( function ( mw, $ ) {

"use strict";

/**
 * Configuration for this script.
 */
var settings = {
	sandboxNamespaceNumber: 4,
	sandboxPageTitle: "User script sandbox",
	storagePrefix: "userScriptSandbox."
};

/**
 * A thin wrapper around localStorage.
 */
var storage = {

	/**
	 * Retrieves a string value from localStorage.
	 * @param selection {String} String key to get the value for.
	 * @param fallback {String} Value to use in case key does not exist (optional).
	 * @return A string value or null.
	 */
	get: function ( selection, fallback ) {
		try {
			var value = localStorage.getItem( settings.storagePrefix + selection );
			return value != null ? value : (fallback != null ? fallback : null);
		} catch (e) {
			// localstorage can always throw exceptions
			return (fallback != null ? fallback : null);
		}
	},

	/**
	 * Sets a key/value pair in localStorage.
	 * @param selection {String} String key to set the value for.
	 * @param value {mixed} String value to set (null or undefined to remove).
	 */
	set: function ( key, value ) {
		try {
			if ( value == null ) {
				localStorage.removeItem( settings.storagePrefix + key );
			} else {
				localStorage.setItem( settings.storagePrefix + key, value );
			}
		} catch (e) {
			// localstorage can always throw exceptions
		}
	}

};

/**
 * The sandbox editor interface code.
 */
var editor = {

	dependencies: ["mediawiki.user", "mediawiki.util", "oojs-ui"],

	/**
	 * Shows the user interface for the sandbox editor.
	 */
	show: function () {
		var enabled = !!+storage.get( "enabled", "0" );
		var dependencies = parseDependencies( storage.get("dependencies", "") );
		var js = storage.get( "js", "" );
		var css = storage.get( "css", "" );
		
		mw.util.addCSS(
			".sandbox-code-input { max-width: none; } " +
			".sandbox-code-input textarea { font-family: monospace, sans-serif; max-height: 100vw; min-height: 5em; }"
		);

		editor.$wrapper = $("#sandbox-wrapper");
		editor.$wrapper.css( 'clear', 'both' );
		editor.$wrapper.empty();
		
		var enabledControl = new OO.ui.ToggleSwitchWidget( { value: enabled } );
		var dependenciesControl = new OO.ui.CapsuleMultiselectWidget( {
			menu: {
				items: mw.loader.getModuleNames().sort().map( function ( name ) {
					return new OO.ui.MenuOptionWidget( {
						data: name,
						label: name
					} );
				} )
			},
			$overlay: editor.$wrapper
		} ).setItemsFromData( dependencies );
		var saveLocalControl = new OO.ui.ButtonWidget( {
			label: 'Save to local storage',
			disabled: true
		} );
		
		var enabledFieldset = new OO.ui.FieldsetLayout( {} );
		enabledFieldset.addItems( [
			new OO.ui.FieldLayout( enabledControl, { label: 'Enable sandbox' } )
		] );
		
		var optionsFieldset = new OO.ui.FieldsetLayout( {} );
		optionsFieldset.addItems( [
			new OO.ui.FieldLayout( dependenciesControl, { label: 'Dependencies' } )
		] );
		
		var jsTextbox = new OO.ui.MultilineTextInputWidget( { classes: [ 'sandbox-code-input' ], dir: 'ltr', rows: 25, value: js } );
		var cssTextbox = new OO.ui.MultilineTextInputWidget( { classes: [ 'sandbox-code-input' ], dir: 'ltr', rows: 25, value: css } );
		var optionsPanel = new OO.ui.TabPanelLayout( 'options', { label: 'Options', expanded: false, framed: true, content: [ optionsFieldset ] } );
		var jsPanel = new OO.ui.TabPanelLayout( 'js', { label: 'JavaScript', expanded: false, framed: true, content: [ jsTextbox ] } );
		var cssPanel = new OO.ui.TabPanelLayout( 'css', { label: 'CSS', expanded: false, framed: true, content: [ cssTextbox ] } );
		
		enabledControl.on( 'change', function ( value ) {
			storage.set( "enabled", value ? "1" : "0" );
		} );
		dependenciesControl.on( 'change', function ( value ) {
			saveLocalControl.setDisabled( false );
		} );
		jsTextbox.on( 'change', function ( value ) {
			saveLocalControl.setDisabled( false );
		} );
		cssTextbox.on( 'change', function ( value ) {
			saveLocalControl.setDisabled( false );
		} );

		var index = new OO.ui.IndexLayout( { expanded: false } );
		index.addTabPanels ( [ optionsPanel, jsPanel, cssPanel ] );

		editor.$wrapper.append( enabledFieldset.$element );
		editor.$wrapper.append( index.$element );
		editor.$wrapper.append( saveLocalControl.$element );

		saveLocalControl.on( 'click', function () {
			saveLocalControl.setDisabled( true );
			storage.set( "dependencies", dependenciesControl.getItemsData().join( ',' ) );
			storage.set( "js", jsTextbox.getValue() );
			storage.set( "css", cssTextbox.getValue() );
		} );

		$("#sandbox-loading").hide();
		editor.$wrapper.show();

	}

};

function parseDependencies( str ) {
	return $.trim( str ).split( /\s*,\s*/ );
}

/**
 * Runs any CSS and JS code from localStorage once dependencies have been satisfied.
 */
function runSandbox() {

	var enabled, css, js, dependencies;

	enabled = +storage.get( "enabled", "0" );
	if ( !enabled ) {
		return;
	}

	css = storage.get( "css", "" );
	js = storage.get( "js", "" );
	dependencies = parseDependencies( storage.get("dependencies", "") );

	mw.loader.using( "mediawiki.util", function () {
		mw.util.addCSS( css );
	});

	mw.loader.using( dependencies[0] ? dependencies : [], function () {
		$.globalEval( js + "\n//# sourceURL=localSandbox.js" );
	});

}

/**
 * Initialization code
 */
function main() {

	// On the sandbox page, run the editor instead of the code in the sandbox.
	if ( mw.config.get("wgAction") === "view" &&
	     mw.config.get("wgNamespaceNumber") === settings.sandboxNamespaceNumber &&
	     mw.config.get("wgTitle") === settings.sandboxPageTitle )
	{

		// Prevent clickjacking.
		if ( window.top !== window.self ) {
			return;
		}

		mw.loader.using( editor.dependencies, function () {
			$( editor.show );
		});

	}
	else
	{
		runSandbox();
	}

}

main();

}( mediaWiki, jQuery ) );