%PDF- %PDF-
| Direktori : /www/varak.net/wiki.varak.net/extensions/VisualEditor/lib/ve/src/init/ |
| Current File : //www/varak.net/wiki.varak.net/extensions/VisualEditor/lib/ve/src/init/ve.init.Target.js |
/*!
* VisualEditor Initialization Target class.
*
* @copyright 2011-2016 VisualEditor Team and others; see http://ve.mit-license.org
*/
/**
* Generic Initialization target.
*
* @class
* @abstract
* @extends OO.ui.Element
* @mixins OO.EventEmitter
*
* @constructor
* @param {Object} [config] Configuration options
* @cfg {Object} [toolbarConfig] Configuration options for the toolbar
*/
ve.init.Target = function VeInitTarget( config ) {
config = config || {};
// Parent constructor
ve.init.Target.super.call( this, config );
// Mixin constructors
OO.EventEmitter.call( this );
// Register
ve.init.target = this;
// Properties
this.surfaces = [];
this.surface = null;
this.toolbar = null;
this.actionsToolbar = null;
this.toolbarConfig = config.toolbarConfig;
this.$scrollContainer = this.getScrollContainer();
this.toolbarScrollOffset = 0;
this.setupTriggerListeners();
// Initialization
this.$element.addClass( 've-init-target' );
if ( ve.init.platform.constructor.static.isInternetExplorer() ) {
this.$element.addClass( 've-init-target-ie' );
}
// We don't have any Edge CSS bugs that aren't present in IE, so
// use a combined class to simplify selectors.
if ( ve.init.platform.constructor.static.isEdge() ) {
this.$element.addClass( 've-init-target-ie-or-edge' );
}
// Events
this.onDocumentKeyDownHandler = this.onDocumentKeyDown.bind( this );
this.onTargetKeyDownHandler = this.onTargetKeyDown.bind( this );
this.onContainerScrollHandler = this.onContainerScroll.bind( this );
this.bindHandlers();
};
/* Inheritance */
OO.inheritClass( ve.init.Target, OO.ui.Element );
OO.mixinClass( ve.init.Target, OO.EventEmitter );
/* Static Properties */
ve.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',
title: OO.ui.deferMsg( 'visualeditor-toolbar-structure' ),
indicator: 'down',
include: [ { group: 'structure' } ],
demote: [ 'outdent', 'indent' ]
},
// Insert
{
header: OO.ui.deferMsg( 'visualeditor-toolbar-insert' ),
type: 'list',
icon: 'add',
label: '',
title: OO.ui.deferMsg( 'visualeditor-toolbar-insert' ),
indicator: 'down',
include: '*'
},
// Special character toolbar
{
header: OO.ui.deferMsg( 'visualeditor-toolbar-insert' ),
include: [ 'specialCharacter' ]
}
];
ve.init.Target.static.actionGroups = [];
/**
* List of commands which can be triggered anywhere from within the document
*
* @type {string[]} List of command names
*/
ve.init.Target.static.documentCommands = [ 'commandHelp' ];
/**
* List of commands which can be triggered from within the target element
*
* @type {string[]} List of command names
*/
ve.init.Target.static.targetCommands = [ 'findAndReplace', 'findNext', 'findPrevious' ];
/**
* List of commands to include in the target
*
* Null means all commands in the registry are used (excluding excludeCommands)
*
* @type {string[]|null} List of command names
*/
ve.init.Target.static.includeCommands = null;
/**
* List of commands to exclude from the target entirely
*
* @type {string[]} List of command names
*/
ve.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}
*/
ve.init.Target.static.importRules = {
external: {
blacklist: [
// Annotations
// TODO: allow spans
'textStyle/span', 'textStyle/font',
// Nodes
'alienInline', 'alienBlock', 'comment'
],
nodeSanitization: true
},
all: null
};
/* Methods */
/**
* Bind event handlers to target and document
*/
ve.init.Target.prototype.bindHandlers = function () {
$( this.getElementDocument() ).on( 'keydown', this.onDocumentKeyDownHandler );
this.$element.on( 'keydown', this.onTargetKeyDownHandler );
this.$scrollContainer.on( 'scroll', this.onContainerScrollHandler );
};
/**
* Unbind event handlers on target and document
*/
ve.init.Target.prototype.unbindHandlers = function () {
$( this.getElementDocument() ).off( 'keydown', this.onDocumentKeyDownHandler );
this.$element.off( 'keydown', this.onTargetKeyDownHandler );
this.$scrollContainer.off( 'scroll', this.onContainerScrollHandler );
};
/**
* Destroy the target
*/
ve.init.Target.prototype.destroy = function () {
this.clearSurfaces();
if ( this.toolbar ) {
this.toolbar.destroy();
this.toolbar = null;
}
if ( this.actionsToolbar ) {
this.actionsToolbar.destroy();
this.actionsToolbar = null;
}
this.$element.remove();
this.unbindHandlers();
ve.init.target = null;
};
/**
* Set up trigger listeners
*/
ve.init.Target.prototype.setupTriggerListeners = function () {
var surfaceOrSurfaceConfig = this.getSurface() || this.getSurfaceConfig();
this.documentTriggerListener = new ve.TriggerListener( this.constructor.static.documentCommands, surfaceOrSurfaceConfig.commandRegistry );
this.targetTriggerListener = new ve.TriggerListener( this.constructor.static.targetCommands, surfaceOrSurfaceConfig.commandRegistry );
};
/**
* Get the target's scroll container
*
* @return {jQuery} The target's scroll container
*/
ve.init.Target.prototype.getScrollContainer = function () {
return $( this.getElementWindow() );
};
/**
* Handle scroll container scroll events
*/
ve.init.Target.prototype.onContainerScroll = function () {
var scrollTop,
toolbar = this.getToolbar();
if ( toolbar.isFloatable() ) {
scrollTop = this.$scrollContainer.scrollTop();
if ( scrollTop + this.toolbarScrollOffset > toolbar.getElementOffset().top ) {
toolbar.float();
} else {
toolbar.unfloat();
}
}
};
/**
* Handle key down events on the document
*
* @param {jQuery.Event} e Key down event
*/
ve.init.Target.prototype.onDocumentKeyDown = function ( e ) {
var command, surface, trigger = new ve.ui.Trigger( e );
if ( trigger.isComplete() ) {
command = this.documentTriggerListener.getCommandByTrigger( trigger.toString() );
surface = this.getSurface();
if ( surface && command && command.execute( surface ) ) {
e.preventDefault();
}
}
};
/**
* Handle key down events on the target
*
* @param {jQuery.Event} e Key down event
*/
ve.init.Target.prototype.onTargetKeyDown = function ( e ) {
var command, surface, trigger = new ve.ui.Trigger( e );
if ( trigger.isComplete() ) {
command = this.targetTriggerListener.getCommandByTrigger( trigger.toString() );
surface = this.getSurface();
if ( surface && command && command.execute( surface ) ) {
e.preventDefault();
}
}
};
/**
* Handle toolbar resize events
*/
ve.init.Target.prototype.onToolbarResize = function () {
this.getSurface().setToolbarHeight( this.getToolbar().getHeight() + this.toolbarScrollOffset );
};
/**
* Create a target widget.
*
* @method
* @param {ve.dm.Document} dmDoc Document model
* @param {Object} [config] Configuration options
* @return {ve.ui.TargetWidget}
*/
ve.init.Target.prototype.createTargetWidget = function ( dmDoc, config ) {
return new ve.ui.TargetWidget( dmDoc, config );
};
/**
* Create a surface.
*
* @method
* @param {ve.dm.Document} dmDoc Document model
* @param {Object} [config] Configuration options
* @return {ve.ui.DesktopSurface}
*/
ve.init.Target.prototype.createSurface = function ( dmDoc, config ) {
return new ve.ui.DesktopSurface( dmDoc, this.getSurfaceConfig( config ) );
};
/**
* Get surface configuration options
*
* @param {Object} config Configuration option overrides
* @return {Object} Surface configuration options
*/
ve.init.Target.prototype.getSurfaceConfig = function ( config ) {
return ve.extendObject( {
$scrollContainer: this.$scrollContainer,
commandRegistry: ve.ui.commandRegistry,
sequenceRegistry: ve.ui.sequenceRegistry,
dataTransferHandlerFactory: ve.ui.dataTransferHandlerFactory,
includeCommands: this.constructor.static.includeCommands,
excludeCommands: OO.simpleArrayUnion(
this.constructor.static.excludeCommands,
this.constructor.static.documentCommands,
this.constructor.static.targetCommands
),
importRules: this.constructor.static.importRules
}, config );
};
/**
* Add a surface to the target
*
* @param {ve.dm.Document} dmDoc Document model
* @param {Object} [config] Configuration options
* @return {ve.ui.DesktopSurface}
*/
ve.init.Target.prototype.addSurface = function ( dmDoc, config ) {
var surface = this.createSurface( dmDoc, config );
this.surfaces.push( surface );
surface.getView().connect( this, {
focus: this.onSurfaceViewFocus.bind( this, surface )
} );
return surface;
};
/**
* Destroy and remove all surfaces from the target
*/
ve.init.Target.prototype.clearSurfaces = function () {
// We're about to destroy this.surface, so unset it for sanity
// Otherwise, getSurface() could return a destroyed surface
this.surface = null;
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
*/
ve.init.Target.prototype.onSurfaceViewFocus = function ( surface ) {
this.setSurface( surface );
};
/**
* Set the target's active surface
*
* @param {ve.ui.Surface} surface Surface
*/
ve.init.Target.prototype.setSurface = function ( surface ) {
if ( this.surfaces.indexOf( surface ) === -1 ) {
throw new Error( 'Active surface must have been added first' );
}
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
*/
ve.init.Target.prototype.getSurface = function () {
return this.surface;
};
/**
* Get the target's toolbar
*
* @return {ve.ui.TargetToolbar} Toolbar
*/
ve.init.Target.prototype.getToolbar = function () {
if ( !this.toolbar ) {
this.toolbar = new ve.ui.PositionedTargetToolbar( this, this.toolbarConfig );
}
return this.toolbar;
};
/**
* Get the actions toolbar
*
* @return {ve.ui.TargetToolbar} Actions toolbar
*/
ve.init.Target.prototype.getActions = function () {
if ( !this.actionsToolbar ) {
this.actionsToolbar = new ve.ui.TargetToolbar( this );
}
return this.actionsToolbar;
};
/**
* Set up the toolbar, attaching it to a surface.
*
* @param {ve.ui.Surface} surface Surface
*/
ve.init.Target.prototype.setupToolbar = function ( surface ) {
var toolbar = this.getToolbar(),
actions = this.getActions(),
rAF = requestAnimationFrame || setTimeout;
toolbar.connect( this, { resize: 'onToolbarResize' } );
toolbar.setup( this.constructor.static.toolbarGroups, surface );
actions.setup( this.constructor.static.actionGroups, surface );
this.attachToolbar( surface );
toolbar.$bar.append( surface.getToolbarDialogs().$element );
toolbar.$actions.append( actions.$element );
rAF( this.onContainerScrollHandler );
};
/**
* Attach the toolbar to the DOM
*/
ve.init.Target.prototype.attachToolbar = function () {
this.getToolbar().$element.insertBefore( this.getToolbar().getSurface().$element );
this.getToolbar().initialize();
this.getActions().initialize();
};