Mooeypoo has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/224971

Change subject: [HACKATHON-WIP] Create an OOUI module for WikiEditor
......................................................................

[HACKATHON-WIP] Create an OOUI module for WikiEditor

Change-Id: Id631290c42a0aba2cc31faf532e24f13eaa0c43c
---
M .jshintrc
M WikiEditor.hooks.php
M extension.json
A modules/ooui-module/mw.wikiEditor.TriggerListener.js
A modules/ooui-module/mw.wikiEditor.init.Target.js
A modules/ooui-module/mw.wikiEditor.js
A modules/ooui-module/mw.wikiEditor.ui.DesktopSurface.js
A modules/ooui-module/mw.wikiEditor.ui.Overlay.js
A modules/ooui-module/mw.wikiEditor.ui.Trigger.js
9 files changed, 1,188 insertions(+), 2 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/WikiEditor 
refs/changes/71/224971/1

diff --git a/.jshintrc b/.jshintrc
index 81d1fa7..daaa348 100644
--- a/.jshintrc
+++ b/.jshintrc
@@ -29,6 +29,7 @@
        "globals": {
                "mediaWiki": false,
                "jQuery": false,
-               "QUnit": false
+               "QUnit": false,
+               "OO": false
        }
 }
diff --git a/WikiEditor.hooks.php b/WikiEditor.hooks.php
index 25e340f..c693889 100644
--- a/WikiEditor.hooks.php
+++ b/WikiEditor.hooks.php
@@ -110,6 +110,11 @@
         * T99257: Extension registration does not properly support 2d arrays 
so set it as a global for now
         */
        public static function onRegistration() {
+               global $wgWikiEditorOOUI;
+               if ( $wgWikiEditorOOUI == true ) {
+
+                       return;
+               }
                // Each module may be configured individually to be globally 
on/off or user preference based
                $features = array(
 
@@ -142,7 +147,6 @@
                } else {
                        $wgWikiEditorFeatures = $features;
                }
-
        }
 
        /**
@@ -235,10 +239,15 @@
         * @return bool
         */
        public static function editPageShowEditFormInitial( $editPage, 
$outputPage ) {
+               global $wgWikiEditorOOUI;
                if ( $editPage->contentModel !== CONTENT_MODEL_WIKITEXT ) {
                        return true;
                }
 
+               if ( $wgWikiEditorOOUI == true ) {
+                       $outputPage->addModules( 'ooui.wikiEditor' );
+                       return true;
+               }
                // Add modules for enabled features
                foreach ( self::$features as $name => $feature ) {
                        if ( !self::isEnabled( $name ) ) {
diff --git a/extension.json b/extension.json
index 0d0ccfe..867995d 100644
--- a/extension.json
+++ b/extension.json
@@ -12,6 +12,9 @@
        "descriptionmsg": "wikieditor-desc",
        "type": "other",
        "callback": "WikiEditorHooks::onRegistration",
+       "config": {
+               "WikiEditorOOUI": false
+       },
        "MessagesDirs": {
                "WikiEditor": [
                        "i18n"
@@ -47,6 +50,12 @@
                ]
        },
        "ResourceModules": {
+               "ooui.wikiEditor": {
+                       "group": "ext.wikiEditor",
+                       "dependencies": [
+                               "oojs-ui"
+                       ]
+               },
                "jquery.wikiEditor": {
                        "group": "ext.wikiEditor",
                        "scripts": "jquery.wikiEditor.js",
diff --git a/modules/ooui-module/mw.wikiEditor.TriggerListener.js 
b/modules/ooui-module/mw.wikiEditor.TriggerListener.js
new file mode 100644
index 0000000..48e3014
--- /dev/null
+++ b/modules/ooui-module/mw.wikiEditor.TriggerListener.js
@@ -0,0 +1,82 @@
+( function ( mw ) {
+       /*!
+        * VisualEditor UserInterface TriggerListener class.
+        *
+        * @copyright 2011-2015 VisualEditor Team and others; see 
http://ve.mit-license.org
+        */
+
+       /**
+        * Trigger listener
+        *
+        * @class
+        *
+        * @constructor
+        * @param {string[]} commands Commands to listen to triggers for
+        */
+       mw.wikiEditor.TriggerListener = function MwWikiEditorUiTriggerListener( 
commands ) {
+               // Properties
+               this.commands = [];
+               this.commandsByTrigger = {};
+               this.triggers = {};
+
+               this.setupCommands( commands );
+       };
+
+       /* Inheritance */
+
+       OO.initClass( mw.wikiEditor.TriggerListener );
+
+       /* Methods */
+
+       /**
+        * Setup commands
+        *
+        * @param {string[]} commands Commands to listen to triggers for
+        */
+       mw.wikiEditor.TriggerListener.prototype.setupCommands = function ( 
commands ) {
+               var i, j, command, triggers;
+               this.commands = commands;
+               if ( commands.length ) {
+                       for ( i = this.commands.length - 1; i >= 0; i-- ) {
+                               command = this.commands[i];
+                               triggers = 
mw.wikiEditor.triggerRegistry.lookup( command );
+                               if ( triggers ) {
+                                       for ( j = triggers.length - 1; j >= 0; 
j-- ) {
+                                               
this.commandsByTrigger[triggers[j].toString()] = 
mw.wikiEditor.commandRegistry.lookup( command );
+                                       }
+                                       this.triggers[command] = triggers;
+                               }
+                       }
+               }
+       };
+
+       /**
+        * Get list of commands.
+        *
+        * @returns {string[]} Commands
+        */
+       mw.wikiEditor.TriggerListener.prototype.getCommands = function () {
+               return this.commands;
+       };
+
+       /**
+        * Get command associated with trigger string.
+        *
+        * @method
+        * @param {string} trigger Trigger string
+        * @returns {ve.ui.Command|undefined} Command
+        */
+       mw.wikiEditor.TriggerListener.prototype.getCommandByTrigger = function 
( trigger ) {
+               return this.commandsByTrigger[trigger];
+       };
+
+       /**
+        * Get triggers for a specified name.
+        *
+        * @param {string} name Trigger name
+        * @returns {ve.ui.Trigger[]|undefined} Triggers
+        */
+       mw.wikiEditor.TriggerListener.prototype.getTriggers = function ( name ) 
{
+               return this.triggers[name];
+       };
+} )( mediaWiki );
diff --git a/modules/ooui-module/mw.wikiEditor.init.Target.js 
b/modules/ooui-module/mw.wikiEditor.init.Target.js
new file mode 100644
index 0000000..b827ed4
--- /dev/null
+++ b/modules/ooui-module/mw.wikiEditor.init.Target.js
@@ -0,0 +1,301 @@
+( function ( mw, $ ) {
+       /*!
+        * VisualEditor Initialization Target class.
+        *
+        * @copyright 2011-2015 VisualEditor Team and others; see 
http://ve.mit-license.org
+        */
+
+       /**
+        * Generic Wikitext initialization target.
+        *
+        * @class
+        * @abstract
+        * @extends OO.ui.Element
+        * @mixins OO.EventEmitter
+        *
+        * @constructor
+        * @param {Object} toolbarConfig Configuration options for the toolbar
+        */
+       mw.wikiEditor.init.Target = function VeInitTarget( toolbarConfig ) {
+               // Parent constructor
+               OO.ui.Element.call( this );
+
+               // Mixin constructors
+               OO.EventEmitter.call( this );
+
+               // Properties
+               this.surfaces = [];
+               mw.wikiEditor.init.target = this;
+               this.surface = null;
+               this.toolbar = null;
+               this.toolbarConfig = toolbarConfig;
+/*             this.documentTriggerListener = new ve.TriggerListener( 
this.constructor.static.documentCommands );
+               this.targetTriggerListener = new ve.TriggerListener( 
this.constructor.static.targetCommands );
+
+               // Initialization
+               this.$element.addClass( 've-init-target' );
+
+               if ( ve.init.platform.constructor.static.isInternetExplorer() ) 
{
+                       this.$element.addClass( 've-init-target-ie' );
+               }
+
+               // Events
+               this.onDocumentKeyDownHandler = this.onDocumentKeyDown.bind( 
this );
+               this.onTargetKeyDownHandler = this.onTargetKeyDown.bind( this );
+               this.bindHandlers();
+
+               // Register
+               ve.init.target = this;*/
+       };
+
+       /* Inheritance */
+
+       OO.inheritClass( mw.wikiEditor.init.Target, OO.ui.Element );
+
+       OO.mixinClass( mw.wikiEditor.init.Target, OO.EventEmitter );
+
+       /* Events */
+
+       /**
+        * @event addSurface
+        * @param {mw.wikiEditor.ui.Surface} surface Added surface
+        */
+
+       /* Static Properties */
+
+       // TODO: Grab VE's toolbar definition
+       mw.wikiEditor.init.Target.static.toolbarGroups = [
+               // History
+               {
+                       header: OO.ui.deferMsg( 'visualeditor-toolbar-history' 
),
+                       include: [ 'undo', 'redo' ]
+               },
+               // Format
+               {
+                       header: OO.ui.deferMsg( 
'visualeditor-toolbar-paragraph-format' ),
+                       type: 'menu',
+                       indicator: 'down',
+                       title: OO.ui.deferMsg( 
'visualeditor-toolbar-format-tooltip' ),
+                       include: [ { group: 'format' } ],
+                       promote: [ 'paragraph' ],
+                       demote: [ 'preformatted', 'blockquote' ]
+               },
+               // Text style
+               {
+                       header: OO.ui.deferMsg( 
'visualeditor-toolbar-text-style' ),
+                       title: OO.ui.deferMsg( 
'visualeditor-toolbar-style-tooltip' ),
+                       include: [ 'bold', 'italic', 'moreTextStyle' ]
+               },
+               // Link
+               {
+                       header: OO.ui.deferMsg( 
'visualeditor-linkinspector-title' ),
+                       include: [ 'link' ]
+               },
+               // Structure
+               {
+                       header: OO.ui.deferMsg( 
'visualeditor-toolbar-structure' ),
+                       type: 'list',
+                       icon: 'listBullet',
+                       indicator: 'down',
+                       include: [ { group: 'structure' } ],
+                       demote: [ 'outdent', 'indent' ]
+               },
+               // Insert
+               {
+                       header: OO.ui.deferMsg( 'visualeditor-toolbar-insert' ),
+                       type: 'list',
+                       icon: 'insert',
+                       label: '',
+                       title: OO.ui.deferMsg( 'visualeditor-toolbar-insert' ),
+                       indicator: 'down',
+                       include: '*'
+               },
+               // Special character toolbar
+               {
+                       header: OO.ui.deferMsg( 'visualeditor-toolbar-insert' ),
+                       include: [ 'specialCharacter' ]
+               },
+               // Table
+               {
+                       header: OO.ui.deferMsg( 'visualeditor-toolbar-table' ),
+                       type: 'list',
+                       icon: 'table',
+                       indicator: 'down',
+                       include: [ { group: 'table' } ],
+                       demote: [ 'deleteTable' ]
+               }
+       ];
+
+       /**
+        * List of commands which can be triggered anywhere from within the 
document
+        *
+        * @type {string[]} List of command names
+        */
+       //mw.wikiEditor.init.Target.static.documentCommands = [ 'commandHelp' ];
+
+       /**
+        * List of commands to exclude from the target entirely
+        *
+        * @type {string[]} List of command names
+        */
+       mw.wikiEditor.init.Target.static.excludeCommands = [];
+
+       /**
+        * Surface import rules
+        *
+        * One set for external (non-VE) paste sources and one for all paste 
sources.
+        *
+        * @see ve.dm.ElementLinearData#sanitize
+        * @type {Object}
+        */
+       // mw.wikiEditor.init.Target.static.importRules = {
+       //      external: {
+       //              blacklist: [
+       //                      // Annotations
+       //                      // TODO: allow spans
+       //                      'textStyle/span', 'textStyle/font',
+       //                      // Nodes
+       //                      'alienInline', 'alienBlock', 'comment'
+       //              ]
+       //      },
+       //      all: null
+       // };
+
+       /* Methods */
+
+       /**
+        * Bind event handlers to target and document
+        */
+       mw.wikiEditor.init.Target.prototype.bindHandlers = function () {
+               $( this.getElementDocument() ).on( 'keydown', 
this.onDocumentKeyDownHandler );
+               this.$element.on( 'keydown', this.onTargetKeyDownHandler );
+       };
+
+       /**
+        * Unbind event handlers on target and document
+        */
+       mw.wikiEditor.init.Target.prototype.unbindHandlers = function () {
+               $( this.getElementDocument() ).off( 'keydown', 
this.onDocumentKeyDownHandler );
+               this.$element.off( 'keydown', this.onTargetKeyDownHandler );
+       };
+
+       /**
+        * Destroy the target
+        */
+       mw.wikiEditor.init.Target.prototype.destroy = function () {
+               this.clearSurfaces();
+               if ( this.toolbar ) {
+                       this.toolbar.destroy();
+                       this.toolbar = null;
+               }
+               this.$element.remove();
+               this.unbindHandlers();
+               mw.wikiEditor.init.target = null;
+       };
+
+       /**
+        * Create a surface.
+        *
+        * @method
+        * @param {ve.dm.Document} dmDoc Document model (Not in use)
+        * @param {Object} [config] Configuration options
+        * @returns {ve.ui.Surface}
+        */
+       mw.wikiEditor.init.Target.prototype.createSurface = function ( dmDoc, 
config ) {
+               // config = ve.extendObject( {
+               //      excludeCommands: OO.simpleArrayUnion(
+               //              this.constructor.static.excludeCommands,
+               //              this.constructor.static.documentCommands,
+               //              this.constructor.static.targetCommands
+               //      ),
+               //      importRules: this.constructor.static.importRules
+               // }, config );
+               return new mw.wikiEditor.ui.DesktopSurface( config );
+       };
+
+       /**
+        * Add a surface to the target
+        *
+        * @param {ve.dm.Document} dmDoc Document model
+        * @param {Object} [config] Configuration options
+        * @fires addSurface
+        * @returns {ve.ui.Surface}
+        */
+       mw.wikiEditor.init.Target.prototype.addSurface = function ( dmDoc, 
config ) {
+               var surface = this.createSurface( dmDoc, config );
+               this.surfaces.push( surface );
+
+               this.emit( 'addSurface', surface );
+               return surface;
+       };
+
+       /**
+        * Destroy and remove all surfaces from the target
+        */
+       mw.wikiEditor.init.Target.clearSurfaces = function () {
+               while ( this.surfaces.length ) {
+                       this.surfaces.pop().destroy();
+               }
+       };
+
+       /**
+        * Handle focus events from a surface's view
+        *
+        * @param {ve.ui.Surface} surface Surface firing the event
+        */
+       mw.wikiEditor.init.Target.prototype.onSurfaceViewFocus = function ( 
surface ) {
+               this.setSurface( surface );
+       };
+
+       /**
+        * Set the target's active surface
+        *
+        * @param {mw.wikiEditor.ui.Surface} surface Surface
+        */
+       mw.wikiEditor.init.Target.prototype.setSurface = function ( surface ) {
+               if ( surface !== this.surface ) {
+                       this.surface = surface;
+                       this.setupToolbar( surface );
+               }
+       };
+
+       /**
+        * Get the target's active surface, if it exists
+        *
+        * @return {ve.ui.Surface|null} Surface
+        */
+       mw.wikiEditor.init.Target.prototype.getSurface = function () {
+               return this.surface;
+       };
+
+       /**
+        * Get the target's toolbar
+        *
+        * @return {ve.ui.TargetToolbar} Toolbar
+        */
+       mw.wikiEditor.init.Target.prototype.getToolbar = function () {
+               if ( !this.toolbar ) {
+                       this.toolbar = new mw.wikiEditor.ui.TargetToolbar( 
this, this.toolbarConfig );
+               }
+               return this.toolbar;
+       };
+
+       /**
+        * Set up the toolbar, attaching it to a surface.
+        *
+        * @param {ve.ui.Surface} surface Surface
+        */
+       mw.wikiEditor.init.Target.prototype.setupToolbar = function ( surface ) 
{
+               this.getToolbar().setup( this.constructor.static.toolbarGroups, 
surface );
+               this.attachToolbar( surface );
+               // TODO: Figure out how to reuse VE dialogs from outside VE
+               // this.getToolbar().$bar.append( 
surface.getToolbarDialogs().$element );
+       };
+
+       /**
+        * Attach the toolbar to the DOM
+        */
+       mw.wikiEditor.init.Target.prototype.attachToolbar = function () {
+               this.getToolbar().$element.insertBefore( 
this.getToolbar().getSurface().$element );
+       };
+} )( mediaWiki, jQuery );
diff --git a/modules/ooui-module/mw.wikiEditor.js 
b/modules/ooui-module/mw.wikiEditor.js
new file mode 100644
index 0000000..19376ff
--- /dev/null
+++ b/modules/ooui-module/mw.wikiEditor.js
@@ -0,0 +1,9 @@
+( function ( mw ) {
+       mw.wikiEditor = {
+               init: {},
+               ui: {}
+       };
+       mw.wikiEditor.triggerRegistry = new OO.Registry();
+       mw.wikiEditor.commandRegistry = new OO.Registry();
+
+} )( mediaWiki );
diff --git a/modules/ooui-module/mw.wikiEditor.ui.DesktopSurface.js 
b/modules/ooui-module/mw.wikiEditor.ui.DesktopSurface.js
new file mode 100644
index 0000000..2d78dfc
--- /dev/null
+++ b/modules/ooui-module/mw.wikiEditor.ui.DesktopSurface.js
@@ -0,0 +1,344 @@
+( function ( mw, $ ) {
+       /*!
+        * VisualEditor UserInterface Surface class.
+        *
+        * @copyright 2011-2015 VisualEditor Team and others; see 
http://ve.mit-license.org
+        */
+
+       /**
+        * A surface is a top-level object which contains both a surface model 
and a surface view.
+        *
+        * @class
+        * @abstract
+        * @extends OO.ui.Element
+        * @mixins OO.EventEmitter
+        *
+        * @constructor
+        * @param {string} data Initial data in the surface
+        * @param {Object} [config] Configuration options
+        * @cfg {string[]} [excludeCommands] List of commands to exclude
+        * @cfg {Object} [importRules] Import rules
+        * @cfg {string} [placeholder] Placeholder text to display when the 
surface is empty
+        * @cfg {string} [inDialog] The name of the dialog this surface is in
+        */
+       mw.wikiEditor.ui.DesktopSurface = function mwWikiEditorUiSurface( data, 
config ) {
+               config = config || {};
+
+               // Parent constructor
+               OO.ui.Element.call( this, config );
+
+               // Mixin constructor
+               OO.EventEmitter.call( this, config );
+
+               this.textInput = new OO.ui.TextInputWidget( {
+                       multiline: true,
+                       placeholder: config.placeholder,
+                       classes: [ 'mw-wikiEditor-ui-textInput' ]
+               } );
+
+               // Properties
+               this.inDialog = config.inDialog || '';
+               this.globalOverlay = new mw.wikiEditor.ui.Overlay( { classes: [ 
'mw-wikiEditor-ui-overlay-global' ] } );
+               this.triggerListener = new mw.wikiEditor.TriggerListener( 
OO.simpleArrayDifference(
+                       Object.keys( mw.wikiEditor.ui.commandRegistry.registry 
), config.excludeCommands || []
+               ) );
+
+               // this.dialogs = this.createDialogWindowManager();
+               this.enabled = true;
+               this.progresses = [];
+               this.showProgressDebounced = OO.ui.debounce( 
this.showProgress.bind( this ) );
+
+               this.toolbarHeight = 0;
+               // TODO: Work with dialogs (make sure they are not dependent on 
VE)
+               // this.toolbarDialogs = new ve.ui.ToolbarDialogWindowManager( 
this, {
+               //      factory: ve.ui.windowFactory,
+               //      modal: false
+               // } );
+
+               // Initialization
+               this.$element
+                       .addClass( 'mw-wikiEditor-ui-desktopSurface' )
+                       .append( this.textInput.$element );
+
+               // this.globalOverlay.$element.append( this.dialogs.$element );
+       };
+
+       /* Inheritance */
+
+       OO.inheritClass( mw.wikiEditor.ui.DesktopSurface, OO.ui.Element );
+
+       OO.mixinClass( mw.wikiEditor.ui.DesktopSurface, OO.EventEmitter );
+
+       /* Events */
+
+       /**
+        * When a surface is destroyed.
+        *
+        * @event destroy
+        */
+
+       /* Methods */
+
+       /**
+        * Destroy the surface, releasing all memory and removing all DOM 
elements.
+        *
+        * @method
+        * @fires destroy
+        */
+       mw.wikiEditor.ui.DesktopSurface.prototype.destroy = function () {
+
+               // Destroy the ce.Surface, the ui.Context and window managers
+               // this.dialogs.destroy();
+               // this.toolbarDialogs.destroy();
+
+               // Remove DOM elements
+               this.$element.remove();
+               this.globalOverlay.$element.remove();
+
+               // Let others know we have been destroyed
+               this.emit( 'destroy' );
+       };
+
+       /**
+        * Initialize surface.
+        *
+        * This must be called after the surface has been attached to the DOM.
+        */
+       mw.wikiEditor.ui.DesktopSurface.prototype.initialize = function () {
+               // Attach globalOverlay to the global <body>, not the local 
frame's <body>
+               $( 'body' ).append( this.globalOverlay.$element );
+       };
+
+       /**
+        * Create a dialog window manager.
+        *
+        * @method
+        * @abstract
+        * @return {ve.ui.WindowManager} Dialog window manager
+        */
+       // ve.ui.Surface.prototype.createDialogWindowManager = null;
+
+       /**
+        * Check if editing is enabled.
+        *
+        * @method
+        * @returns {boolean} Editing is enabled
+        */
+       mw.wikiEditor.ui.DesktopSurface.prototype.isEnabled = function () {
+               return this.enabled;
+       };
+
+       /**
+        * Get dialogs window set.
+        *
+        * @method
+        * @returns {ve.ui.WindowManager} Dialogs window set
+        */
+       // mw.wikiEditor.ui.DesktopSurface.prototype.getDialogs = function () {
+       //      return this.dialogs;
+       // };
+
+       /**
+        * Get toolbar dialogs window set.
+        * @returns {ve.ui.WindowManager} Toolbar dialogs window set
+        */
+       // ve.ui.Surface.prototype.getToolbarDialogs = function () {
+       //      return this.toolbarDialogs;
+       // };
+
+       /**
+        * Get the global overlay.
+        *
+        * Global overlays are attached to the top-most frame.
+        *
+        * @method
+        * @returns {ve.ui.Overlay} Global overlay
+        */
+       mw.wikiEditor.ui.DesktopSurface.prototype.getGlobalOverlay = function 
() {
+               return this.globalOverlay;
+       };
+
+       /**
+        * Disable editing.
+        *
+        * @method
+        */
+       mw.wikiEditor.ui.DesktopSurface.prototype.disable = function () {
+               this.enabled = false;
+               this.textInput.setDisabled( !this.enabled );
+       };
+
+       /**
+        * Enable editing.
+        *
+        * @method
+        */
+       mw.wikiEditor.ui.DesktopSurface.prototype.enable = function () {
+               this.enabled = true;
+               this.textInput.setDisabled( !this.enabled );
+       };
+
+       /**
+        * Execute an action or command.
+        *
+        * @method
+        * @param {ve.ui.Trigger|string} triggerOrAction Trigger or symbolic 
name of action
+        * @param {string} [method] Action method name
+        * @param {Mixed...} [args] Additional arguments for action
+        * @returns {boolean} Action or command was executed
+        */
+       ve.ui.Surface.prototype.execute = function ( triggerOrAction, method ) {
+               var command, obj, ret;
+
+               if ( !this.enabled ) {
+                       return;
+               }
+
+               if ( triggerOrAction instanceof ve.ui.Trigger ) {
+                       command = this.triggerListener.getCommandByTrigger( 
triggerOrAction.toString() );
+                       if ( command ) {
+                               // Have command call execute with action 
arguments
+                               return command.execute( this );
+                       }
+               } else if ( typeof triggerOrAction === 'string' && typeof 
method === 'string' ) {
+                       // Validate method
+                       if ( ve.ui.actionFactory.doesActionSupportMethod( 
triggerOrAction, method ) ) {
+                               // Create an action object and execute the 
method on it
+                               obj = ve.ui.actionFactory.create( 
triggerOrAction, this );
+                               ret = obj[method].apply( obj, 
Array.prototype.slice.call( arguments, 2 ) );
+                               return ret === undefined || !!ret;
+                       }
+               }
+               return false;
+       };
+
+       /**
+        * Set the current height of the toolbar.
+        *
+        * Used for scroll-into-view calculations.
+        *
+        * @param {number} toolbarHeight Toolbar height
+        */
+       ve.ui.Surface.prototype.setToolbarHeight = function ( toolbarHeight ) {
+               this.toolbarHeight = toolbarHeight;
+       };
+
+       /**
+        * Create a progress bar in the progress dialog
+        *
+        * @param {jQuery.Promise} progressCompletePromise Promise which 
resolves when the progress action is complete
+        * @param {jQuery|string|Function} label Progress bar label
+        * @return {jQuery.Promise} Promise which resolves with a progress bar 
widget and a promise which fails if cancelled
+        */
+       ve.ui.Surface.prototype.createProgress = function ( 
progressCompletePromise, label ) {
+               var progressBarDeferred = $.Deferred();
+
+               this.progresses.push( {
+                       label: label,
+                       progressCompletePromise: progressCompletePromise,
+                       progressBarDeferred: progressBarDeferred
+               } );
+
+               this.showProgressDebounced();
+
+               return progressBarDeferred.promise();
+       };
+
+       ve.ui.Surface.prototype.showProgress = function () {
+               var dialogs = this.dialogs,
+                       progresses = this.progresses;
+
+               dialogs.openWindow( 'progress', { progresses: progresses } );
+               this.progresses = [];
+       };
+
+       /**
+        * Get sanitization rules for rich paste
+        *
+        * @returns {Object} Import rules
+        */
+       ve.ui.Surface.prototype.getImportRules = function () {
+               return this.importRules;
+       };
+
+       /**
+        * Surface 'dir' property (GUI/User-Level Direction)
+        *
+        * @returns {string} 'ltr' or 'rtl'
+        */
+       ve.ui.Surface.prototype.getDir = function () {
+               return this.$element.css( 'direction' );
+       };
+
+       ve.ui.Surface.prototype.initFilibuster = function () {
+               var surface = this;
+               this.filibuster = new ve.Filibuster()
+                       .wrapClass( ve.EventSequencer )
+                       .wrapNamespace( ve.dm, 've.dm', [
+                               // blacklist
+                               ve.dm.LinearSelection.prototype.getDescription,
+                               ve.dm.TableSelection.prototype.getDescription,
+                               ve.dm.NullSelection.prototype.getDescription
+                       ] )
+                       .wrapNamespace( ve.ce, 've.ce' )
+                       .wrapNamespace( ve.ui, 've.ui', [
+                               // blacklist
+                               ve.ui.Surface.prototype.startFilibuster,
+                               ve.ui.Surface.prototype.stopFilibuster
+                       ] )
+                       .setObserver( 'dm doc', function () {
+                               return JSON.stringify( 
ve.Filibuster.static.clonePlain(
+                                       surface.model.documentModel.data.data
+                               ) );
+                       } )
+                       .setObserver( 'dm selection', function () {
+                               var selection = surface.model.selection;
+                               if ( !selection ) {
+                                       return null;
+                               }
+                               return selection.getDescription();
+                       } )
+                       .setObserver( 'DOM doc', function () {
+                               return ve.serializeNodeDebug( 
surface.view.$element[0] );
+                       } )
+                       .setObserver( 'DOM selection', function () {
+                               var nativeRange,
+                                       nativeSelection = 
surface.view.nativeSelection;
+                               if ( nativeSelection.rangeCount === 0 ) {
+                                       return null;
+                               }
+                               nativeRange = nativeSelection.getRangeAt( 0 );
+                               return JSON.stringify( {
+                                       startContainer: ve.serializeNodeDebug( 
nativeRange.startContainer ),
+                                       startOffset: nativeRange.startOffset,
+                                       endContainer: (
+                                               nativeRange.startContainer === 
nativeRange.endContainer ?
+                                               '(=startContainer)' :
+                                               ve.serializeNodeDebug( 
nativeRange.endContainer )
+                                       ),
+                                       endOffset: nativeRange.endOffset
+                               } );
+                       } );
+       };
+
+       ve.ui.Surface.prototype.startFilibuster = function () {
+               if ( !this.filibuster ) {
+                       this.initFilibuster();
+               } else {
+                       this.filibuster.clearLogs();
+               }
+               this.filibuster.start();
+       };
+
+       ve.ui.Surface.prototype.stopFilibuster = function () {
+               this.filibuster.stop();
+       };
+
+       /**
+        * Get the name of the dialog this surface is in
+        * @return {string} The name of the dialog this surface is in
+        */
+       ve.ui.Surface.prototype.getInDialog = function () {
+               return this.inDialog;
+       };
+} )( mediaWiki, jQuery );
diff --git a/modules/ooui-module/mw.wikiEditor.ui.Overlay.js 
b/modules/ooui-module/mw.wikiEditor.ui.Overlay.js
new file mode 100644
index 0000000..27bfca0
--- /dev/null
+++ b/modules/ooui-module/mw.wikiEditor.ui.Overlay.js
@@ -0,0 +1,27 @@
+/*!
+ * VisualEditor UserInterface Overlay class.
+ *
+ * @copyright 2011-2015 VisualEditor Team and others; see 
http://ve.mit-license.org
+ */
+
+/**
+ * Container for content that should appear in front of everything else.
+ *
+ * @class
+ * @abstract
+ * @extends OO.ui.Element
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ */
+mw.wikiEditor.ui.Overlay = function MwWikiEditorUiOverlay( config ) {
+       // Parent constructor
+       OO.ui.Element.call( this, config );
+
+       // Initialization
+       this.$element.addClass( 'mw-wikiEditor-ui-overlay' );
+};
+
+/* Inheritance */
+
+OO.inheritClass( mw.wikiEditor.ui.Overlay, OO.ui.Element );
diff --git a/modules/ooui-module/mw.wikiEditor.ui.Trigger.js 
b/modules/ooui-module/mw.wikiEditor.ui.Trigger.js
new file mode 100644
index 0000000..1a1c39b
--- /dev/null
+++ b/modules/ooui-module/mw.wikiEditor.ui.Trigger.js
@@ -0,0 +1,404 @@
+( function ( mw, $ ) {
+       /*!
+        * VisualEditor UserInterface Trigger class.
+        *
+        * @copyright 2011-2015 VisualEditor Team and others; see 
http://ve.mit-license.org
+        */
+
+       /**
+        * Key trigger.
+        *
+        * @class
+        *
+        * @constructor
+        * @param {jQuery.Event|string} [e] Event or string to create trigger 
from
+        * @param {boolean} [allowInvalidPrimary] Allow invalid primary keys
+        */
+       mw.wikiEditor.ui.Trigger = function MwWikiEditorUiTrigger( e, 
allowInvalidPrimary ) {
+               // Properties
+               this.modifiers = {
+                       meta: false,
+                       ctrl: false,
+                       alt: false,
+                       shift: false
+               };
+               this.primary = false;
+
+               // Initialization
+               var i, len, key, parts,
+                       keyAliases = mw.wikiEditor.ui.Trigger.static.keyAliases,
+                       primaryKeys = 
mw.wikiEditor.ui.Trigger.static.primaryKeys,
+                       primaryKeyMap = 
mw.wikiEditor.ui.Trigger.static.primaryKeyMap;
+               if ( e instanceof jQuery.Event ) {
+                       this.modifiers.meta = e.metaKey || false;
+                       this.modifiers.ctrl = e.ctrlKey || false;
+                       this.modifiers.alt = e.altKey || false;
+                       this.modifiers.shift = e.shiftKey || false;
+                       this.primary = primaryKeyMap[e.which] || false;
+               } else if ( typeof e === 'string' ) {
+                       // Normalization: remove whitespace and force lowercase
+                       parts = e.replace( /\s*/g, '' ).toLowerCase().split( 
'+' );
+                       for ( i = 0, len = parts.length; i < len; i++ ) {
+                               key = parts[i];
+                               // Resolve key aliases
+                               if ( Object.prototype.hasOwnProperty.call( 
keyAliases, key ) ) {
+                                       key = keyAliases[key];
+                               }
+                               // Apply key to trigger
+                               if ( Object.prototype.hasOwnProperty.call( 
this.modifiers, key ) ) {
+                                       // Modifier key
+                                       this.modifiers[key] = true;
+                               } else if ( primaryKeys.indexOf( key ) !== -1 
|| allowInvalidPrimary ) {
+                                       // WARNING: Only the last primary key 
will be used
+                                       this.primary = key;
+                               }
+                       }
+               }
+       };
+
+       /* Inheritance */
+
+       OO.initClass( mw.wikiEditor.ui.Trigger );
+
+       /* Static Properties */
+
+       /**
+        * Symbolic modifier key names.
+        *
+        * The order of this array affects the canonical order of a trigger 
string.
+        *
+        * @static
+        * @property
+        * @inheritable
+        */
+       mw.wikiEditor.ui.Trigger.static.modifierKeys = [ 'meta', 'ctrl', 'alt', 
'shift' ];
+
+       /**
+        * Symbolic primary key names.
+        *
+        * @static
+        * @property
+        * @inheritable
+        */
+       mw.wikiEditor.ui.Trigger.static.primaryKeys = [
+               // Special keys
+               'backspace',
+               'tab',
+               'enter',
+               'escape',
+               'page-up',
+               'page-down',
+               'end',
+               'home',
+               'left',
+               'up',
+               'right',
+               'down',
+               'delete',
+               'clear',
+               // Numbers
+               '0',
+               '1',
+               '2',
+               '3',
+               '4',
+               '5',
+               '6',
+               '7',
+               '8',
+               '9',
+               // Letters
+               'a',
+               'b',
+               'c',
+               'd',
+               'e',
+               'f',
+               'g',
+               'h',
+               'i',
+               'j',
+               'k',
+               'l',
+               'm',
+               'n',
+               'o',
+               'p',
+               'q',
+               'r',
+               's',
+               't',
+               'u',
+               'v',
+               'w',
+               'x',
+               'y',
+               'z',
+               // Numpad special keys
+               'multiply',
+               'add',
+               'subtract',
+               'decimal',
+               'divide',
+               // Function keys
+               'f1',
+               'f2',
+               'f3',
+               'f4',
+               'f5',
+               'f6',
+               'f7',
+               'f8',
+               'f9',
+               'f10',
+               'f11',
+               'f12',
+               // Punctuation
+               ';',
+               '=',
+               ',',
+               '-',
+               '.',
+               '/',
+               '`',
+               '[',
+               '\\',
+               ']',
+               '\''
+       ];
+
+       /**
+        * Filter to use when rendering string for a specific platform.
+        *
+        * @static
+        * @property
+        * @inheritable
+        */
+       mw.wikiEditor.ui.Trigger.static.platformFilters = {
+               mac: ( function () {
+                       var names = {
+                               meta: '⌘',
+                               shift: '⇧',
+                               backspace: '⌫',
+                               ctrl: '^',
+                               alt: '⎇',
+                               escape: '⎋'
+                       };
+                       return function ( keys ) {
+                               var i, len;
+                               for ( i = 0, len = keys.length; i < len; i++ ) {
+                                       keys[i] = names[keys[i]] || keys[i];
+                               }
+                               return keys.join( '' ).toUpperCase();
+                       };
+               } )()
+       };
+
+       /**
+        * Aliases for modifier or primary key names.
+        *
+        * @static
+        * @property
+        * @inheritable
+        */
+       mw.wikiEditor.ui.Trigger.static.keyAliases = {
+               // Platform differences
+               command: 'meta',
+               apple: 'meta',
+               windows: 'meta',
+               option: 'alt',
+               return: 'enter',
+               // Shorthand
+               esc: 'escape',
+               cmd: 'meta',
+               del: 'delete',
+               // Longhand
+               control: 'ctrl',
+               alternate: 'alt',
+               // Symbols
+               '⌘': 'meta',
+               '⎇': 'alt',
+               '⇧': 'shift',
+               '⏎': 'enter',
+               '⌫': 'backspace',
+               '⎋': 'escape'
+       };
+
+       /**
+        * Mapping of key codes and symbolic key names.
+        *
+        * @static
+        * @property
+        * @inheritable
+        */
+       mw.wikiEditor.ui.Trigger.static.primaryKeyMap = {
+               // Special keys
+               8: 'backspace',
+               9: 'tab',
+               12: 'clear',
+               13: 'enter',
+               27: 'escape',
+               33: 'page-up',
+               34: 'page-down',
+               35: 'end',
+               36: 'home',
+               37: 'left',
+               38: 'up',
+               39: 'right',
+               40: 'down',
+               46: 'delete',
+               // Numbers
+               48: '0',
+               49: '1',
+               50: '2',
+               51: '3',
+               52: '4',
+               53: '5',
+               54: '6',
+               55: '7',
+               56: '8',
+               57: '9',
+               // Punctuation
+               59: ';',
+               61: '=',
+               // Letters
+               65: 'a',
+               66: 'b',
+               67: 'c',
+               68: 'd',
+               69: 'e',
+               70: 'f',
+               71: 'g',
+               72: 'h',
+               73: 'i',
+               74: 'j',
+               75: 'k',
+               76: 'l',
+               77: 'm',
+               78: 'n',
+               79: 'o',
+               80: 'p',
+               81: 'q',
+               82: 'r',
+               83: 's',
+               84: 't',
+               85: 'u',
+               86: 'v',
+               87: 'w',
+               88: 'x',
+               89: 'y',
+               90: 'z',
+               // Numpad numbers
+               96: '0',
+               97: '1',
+               98: '2',
+               99: '3',
+               100: '4',
+               101: '5',
+               102: '6',
+               103: '7',
+               104: '8',
+               105: '9',
+               // Numpad special keys
+               106: 'multiply',
+               107: 'add',
+               109: 'subtract',
+               110: 'decimal',
+               111: 'divide',
+               // Function keys
+               112: 'f1',
+               113: 'f2',
+               114: 'f3',
+               115: 'f4',
+               116: 'f5',
+               117: 'f6',
+               118: 'f7',
+               119: 'f8',
+               120: 'f9',
+               121: 'f10',
+               122: 'f11',
+               123: 'f12',
+               // Punctuation
+               186: ';',
+               187: '=',
+               188: ',',
+               189: '-',
+               190: '.',
+               191: '/',
+               192: '`',
+               219: '[',
+               220: '\\',
+               221: ']',
+               222: '\''
+       };
+
+       /* Methods */
+
+       /**
+        * Check if trigger is complete.
+        *
+        * For a trigger to be complete, there must be a valid primary key.
+        *
+        * @returns {boolean} Trigger is complete
+        */
+       mw.wikiEditor.ui.Trigger.prototype.isComplete = function () {
+               return this.primary !== false;
+       };
+
+       /**
+        * Get a trigger string.
+        *
+        * Trigger strings are canonical representations of triggers made up of 
the symbolic names of all
+        * active modifier keys and the primary key joined together with a '+' 
sign.
+        *
+        * To normalize a trigger string simply create a new trigger from a 
string and then run this method.
+        *
+        * An incomplete trigger will return an empty string.
+        *
+        * @returns {string} Canonical trigger string
+        */
+       mw.wikiEditor.ui.Trigger.prototype.toString = function () {
+               var i, len,
+                       modifierKeys = 
mw.wikiEditor.ui.Trigger.static.modifierKeys,
+                       keys = [];
+               // Add modifier keywords in the correct order
+               for ( i = 0, len = modifierKeys.length; i < len; i++ ) {
+                       if ( this.modifiers[modifierKeys[i]] ) {
+                               keys.push( modifierKeys[i] );
+                       }
+               }
+               // Check that there were modifiers and the primary key is 
whitelisted
+               if ( this.primary ) {
+                       // Add a symbolic name for the primary key
+                       keys.push( this.primary );
+                       return keys.join( '+' );
+               }
+               // Alternatively return an empty string
+               return '';
+       };
+
+       /**
+        * Get a trigger message.
+        *
+        * This is similar to #toString but the resulting string will be 
formatted in a way that makes it
+        * appear more native for the platform.
+        *
+        * @returns {string} Message for trigger
+        */
+       mw.wikiEditor.ui.Trigger.prototype.getMessage = function () {
+               var keys,
+                       platformFilters = 
mw.wikiEditor.ui.Trigger.static.platformFilters,
+                       // platform = ve.getSystemPlatform();
+                       // HACK: This should be done better, but we don't want 
to copy
+                       // platform over too
+                       platform = $.client.profile().platform;
+
+               keys = this.toString().split( '+' );
+               if ( Object.prototype.hasOwnProperty.call( platformFilters, 
platform ) ) {
+                       return platformFilters[platform]( keys );
+               }
+               return keys.map( function ( key ) {
+                       return key[0].toUpperCase() + key.slice( 1 
).toLowerCase();
+               } ).join( '+' );
+       };
+} )( mediaWiki, jQuery );

-- 
To view, visit https://gerrit.wikimedia.org/r/224971
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: Id631290c42a0aba2cc31faf532e24f13eaa0c43c
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/WikiEditor
Gerrit-Branch: master
Gerrit-Owner: Mooeypoo <mor...@gmail.com>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to