GCPedia Ace Editor

Use the Ace Editor when editing things on GCPedia

当前为 2018-03-06 提交的版本,查看 最新版本

// ==UserScript==
// @name         GCPedia Ace Editor
// @namespace    https://greasyfork.org/users/649
// @version      1.2
// @description  Use the Ace Editor when editing things on GCPedia
// @author       Adrien Pyke
// @match        http://www.gcpedia.gc.ca/*
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_registerMenuCommand
// @grant        unsafeWindow
// @require      https://cdn.rawgit.com/fuzetsu/userscripts/477063e939b9658b64d2f91878da20a7f831d98b/wait-for-elements/wait-for-elements.js
// ==/UserScript==

(() => {
	'use strict';

	const SCRIPT_NAME = 'GCPedia Ace Editor';

	const Util = {
		log(...args) {
			args.unshift(`%c${SCRIPT_NAME}:`, 'font-weight: bold;color: #233c7b;');
			console.log(...args);
		},
		q(query, context = document) {
			return context.querySelector(query);
		},
		qq(query, context = document) {
			return Array.from(context.querySelectorAll(query));
		},
		addScript(src, onload) {
			let s = document.createElement('script');
			s.onload = onload;
			s.src = src;
			document.body.appendChild(s);
		},
		addScriptText(code, onload) {
			let s = document.createElement('script');
			s.onload = onload;
			s.textContent = code;
			document.body.appendChild(s);
		},
		appendStyle(css) {
			let out = '';
			for (let selector in css) {
				out += `${selector}{`;
				for (let rule in css[selector]) {
					out += `${rule}:${css[selector][rule]}!important;`;
				}
				out += '}';
			}

			let style = document.createElement('style');
			style.type = 'text/css';
			style.appendChild(document.createTextNode(out));
			document.head.appendChild(style);
		},
		appendAfter(elem, elemToAppend) {
			elem.parentNode.insertBefore(elemToAppend, elem.nextElementSibling);
		}
	};

	const Config = {
		load() {
			let defaults = {
				theme: 'monokai'
			};

			let cfg = GM_getValue('cfg');
			if (!cfg) return defaults;

			cfg = JSON.parse(cfg);
			for (let property in defaults) {
				if (defaults.hasOwnProperty(property)) {
					if (!cfg[property]) {
						cfg[property] = defaults[property];
					}
				}
			}

			return cfg;
		},

		save(cfg) {
			GM_setValue('cfg', JSON.stringify(cfg));
		},

		setup(editor) {
			const createContainer = function() {
				let div = document.createElement('div');
				div.style.backgroundColor = 'white';
				div.style.padding = '5px';
				div.style.border = '1px solid black';
				div.style.position = 'fixed';
				div.style.top = '0';
				div.style.right = '0';
				div.style.zIndex = 99999;
				return div;
			};

			const createSelect = function(label, options, value) {
				let select = document.createElement('select');
				select.style.margin = '2px';
				let optgroup = document.createElement('optgroup');
				if (label) {
					optgroup.setAttribute('label', label);
				}
				select.appendChild(optgroup);
				options.forEach(opt => {
					let option = document.createElement('option');
					option.setAttribute('value', opt);
					option.textContent = opt;
					optgroup.appendChild(option);
				});
				select.value = value;
				return select;
			};

			const createButton = function(text, onclick) {
				let button = document.createElement('button');
				button.style.margin = '2px';
				button.textContent = text;
				button.onclick = onclick;
				return button;
			};

			const createLabel = function(label) {
				let lbl = document.createElement('span');
				lbl.textContent = label;
				return lbl;
			};

			const createLineBreak = function() {
				return document.createElement('br');
			};

			const init = function(cfg) {
				let div = createContainer();

				let theme = createSelect('Theme', [
					'ambiance',
					'chaos',
					'chrome',
					'clouds',
					'clouds_midnight',
					'cobalt',
					'crimson_editor',
					'dawn',
					'dreamweaver',
					'eclipse',
					'github',
					'gob',
					'gruvbox',
					'idle_fingers',
					'iplastic',
					'katzenmilch',
					'kr_theme',
					'kuroir',
					'merbivore',
					'merbivore_soft',
					'mono_industrial',
					'monokai',
					'pastel_on_dark',
					'solarized_dark',
					'solarized_light',
					'sqlserver',
					'terminal',
					'textmate',
					'tomorrow',
					'tomorrow_night',
					'tomorrow_night_blue',
					'tomorrow_night_bright',
					'tomorrow_night_eighties',
					'twilight',
					'vibrant_ink',
					'xcode'
				], cfg.theme);
				div.appendChild(createLabel('Theme: '));
				div.appendChild(theme);
				div.appendChild(createLineBreak());

				theme.onchange = () => {
					editor.setTheme(`ace/theme/${theme.value}`);
				};

				div.appendChild(createButton('Save', () => {
					let settings = {
						theme: theme.value
					};
					Config.save(settings);
					div.remove();
				}));

				div.appendChild(createButton('Cancel', () => {
					editor.setTheme(`ace/theme/${cfg.theme}`);
					div.remove();
				}));

				document.body.appendChild(div);
			};
			init(Config.load());
		}
	};

	waitForElems({
		sel: '#wpTextbox1',
		stop: true,
		onmatch(textArea) {
			let wrapper = document.createElement('div');
			wrapper.id = 'ace';
			wrapper.textContent = textArea.value;

			Util.appendAfter(textArea, wrapper);

			Util.appendStyle({
				'.ace_editor': {
					height: '600px'
				},
				'.wikiEditor-ui, #wpTextbox1': {
					display: 'none'
				}
			});
			Util.addScript('https://cdnjs.cloudflare.com/ajax/libs/ace/1.2.8/ace.js', () => {
				let editor = unsafeWindow.ace.edit('ace');
				editor.setTheme(`ace/theme/${Config.load().theme}`);
				editor.getSession().setMode('ace/mode/html');
				editor.resize();

				unsafeWindow.aceEditor = editor;
				unsafeWindow.originalTextArea = textArea;

				Util.addScriptText('aceEditor.getSession().on(\'change\', function(){originalTextArea.value = aceEditor.getValue()})');

				GM_registerMenuCommand('GCPedia Ace Editor Settings', () => {
					Config.setup(editor);
				});
			});
		}
	});
})();