JSDuck: Generated code documentation!
See CODING.md for how to run it.
Mistakes fixed:
* Warning: Unknown type function
-> Function
* Warning: Unknown type DOMElement
-> HTMLElement
* Warning: Unknown type DOM Node
-> HTMLElement
* Warning: Unknown type Integer
-> Mixed
* Warning: Unknown type Command
-> ve.Command
* Warning: Unknown type any
-> number
* Warning: Unknown type ve.Transaction
-> ve.dm.Transaction
* Warning: Unknown type ve.dm.AnnotationSet
-> ve.AnnotationSet
* Warning: Unknown type false
-> boolean
* Warning: Unknown type ve.dm.AlienNode
ve.dm doesn't have a generic AlienNode like ve.ce
-> Unknown type ve.dm.AlienInlineNode|ve.dm.AlienBlockNode
* Warning: Unknown type ve.ve.Surface
-> ve.ce.Surface
* ve.example.lookupNode:
-> Last @param should be @return
* ve.dm.Transaction.prototype.pushReplace:
-> @param {Array] should be @param {Array}
* Warning: ve.BranchNode.js:27: {@link ve.Node#hasChildren} links to non-existing member
-> (removed)
* Warning: ve.LeafNode.js:21: {@link ve.Node#hasChildren} links to non-existing member
-> (removed)
Differences fixed:
* Variadic arguments are like @param {Type...} [name]
instead of @param {Type} [name...]
* Convert all file headers from /** to /*! because JSDuck tries
to parse all /** blocks and fails to parse with all sorts of
errors for "Global property", "Unnamed property", and
"Duplicate property".
Find: \/\*\*([^@]+)(@copyright)
Replace: /*!$1$2
* Indented blocks are considered code examples.
A few methods had documentation with numbered lists that were
indented, which have now been updated to not be intended.
* The free-form text descriptions are parsed with Markdown,
which requires lists to be separated from paragraphs by an
empty line.
And we should use `backticks` instead of {braces} for inline
code in text paragraphs.
* Doc blocks for classes and their constructor have to be
in the correct order (@constructor, @param, @return must be
before @class, @abstract, @extends etc.)
* `@extends Class` must not have Class {wrapped}
* @throws must start with a {Type}
* @example means something else. It is used for an inline demo
iframe, not code block. For that simply indent with spaces.
* @member means something else.
Non-function properties are marked with @property, not @member.
* To create a link to a class or member, in most cases the name
is enough to create a link. E.g. Foo, Foo.bar, Foo.bar#quux,
where a hash stands for "instance member", so Foo.bar#quux,
links to Foo.bar.prototype.quux (the is not supported, as
"prototype" is considered an implementation detail, it only
indexes class name and method name).
If the magic linker doesn't work for some case, the
verbose syntax is {@link #target label}.
* @property can't have sub-properties (nested @param and @return
values are supported, only @static @property can't be nested).
We only have one case of this, which can be worked around by
moving those in a new virtual class. The code is unaltered
(only moved down so that it isn't with the scope of the main
@class block). ve.dm.TransactionProcessor.processors.
New:
* @mixins: Classes mixed into the current class.
* @event: Events that can be emitted by a class. These are also
inherited by subclasses. (+ @param, @return and @preventable).
So ve.Node#event-attach is inherited to ve.dm.BreakNode,
just like @method is.
* @singleton: Plain objects such as ve, ve.dm, ve.ce were missing
documentation causing a tree error. Documented those as a
JSDuck singleton, which they but just weren't documented yet.
NB: Members of @singleton don't need @static (if present,
triggers a compiler warning).
* @chainable: Shorthand for "@return this". We were using
"@return {classname}" which is ambiguous (returns the same
instance or another instance?), @chainable is specifically
for "@return this". Creates proper labels in the generated
HTML pages.
Removed:
* @mixin: (not to be confused with @mixins). Not supported by
JSDuck. Every class is standalone anyway. Where needed marked
them @class + @abstract instead.
Change-Id: I6a7c9e8ee8f995731bc205d666167874eb2ebe23
2013-01-04 08:54:17 +00:00
|
|
|
/*!
|
2013-01-15 23:38:49 +00:00
|
|
|
* VisualEditor ContentEditable Surface class.
|
2012-07-19 21:25:16 +00:00
|
|
|
*
|
2013-02-19 23:37:34 +00:00
|
|
|
* @copyright 2011-2013 VisualEditor Team and others; see AUTHORS.txt
|
2012-07-19 00:11:26 +00:00
|
|
|
* @license The MIT License (MIT); see LICENSE.txt
|
|
|
|
*/
|
2013-01-15 20:15:17 +00:00
|
|
|
/*global rangy */
|
2012-07-19 00:11:26 +00:00
|
|
|
|
2012-02-07 19:13:19 +00:00
|
|
|
/**
|
2012-06-20 01:20:28 +00:00
|
|
|
* ContentEditable surface.
|
2012-03-07 19:33:00 +00:00
|
|
|
*
|
2012-02-07 19:13:19 +00:00
|
|
|
* @class
|
2013-10-09 20:09:59 +00:00
|
|
|
* @extends OO.ui.Element
|
2013-10-15 11:58:04 +00:00
|
|
|
* @mixins OO.EventEmitter
|
2013-05-01 22:21:32 +00:00
|
|
|
*
|
2012-02-07 19:13:19 +00:00
|
|
|
* @constructor
|
2012-09-17 13:30:50 +00:00
|
|
|
* @param {jQuery} $container
|
2013-01-15 23:38:49 +00:00
|
|
|
* @param {ve.dm.Surface} model Surface model to observe
|
2013-05-14 23:45:42 +00:00
|
|
|
* @param {ve.ui.Surface} surface Surface user interface
|
2013-09-25 10:21:09 +00:00
|
|
|
* @param {Object} [config] Configuration options
|
2012-02-07 19:13:19 +00:00
|
|
|
*/
|
2013-05-14 23:45:42 +00:00
|
|
|
ve.ce.Surface = function VeCeSurface( model, surface, options ) {
|
2013-09-07 00:59:42 +00:00
|
|
|
var $documentNode;
|
2013-05-14 23:45:42 +00:00
|
|
|
// Parent constructor
|
2013-10-09 20:09:59 +00:00
|
|
|
OO.ui.Element.call( this, options );
|
2013-05-14 23:45:42 +00:00
|
|
|
|
2013-05-01 22:21:32 +00:00
|
|
|
// Mixin constructors
|
2013-10-15 11:58:04 +00:00
|
|
|
OO.EventEmitter.call( this );
|
2012-02-07 19:13:19 +00:00
|
|
|
|
|
|
|
// Properties
|
2012-10-24 22:20:41 +00:00
|
|
|
this.surface = surface;
|
2012-10-11 18:31:28 +00:00
|
|
|
this.inIme = false;
|
2012-02-07 19:13:19 +00:00
|
|
|
this.model = model;
|
2012-10-05 00:08:26 +00:00
|
|
|
this.documentView = new ve.ce.Document( model.getDocument(), this );
|
|
|
|
this.surfaceObserver = new ve.ce.SurfaceObserver( this.documentView );
|
2012-06-20 01:20:28 +00:00
|
|
|
this.selectionTimeout = null;
|
2013-11-01 19:45:59 +00:00
|
|
|
this.$document = this.$( this.getElementDocument() );
|
2013-09-07 00:59:42 +00:00
|
|
|
this.eventSequencer = new ve.EventSequencer( [
|
|
|
|
'keydown', 'keypress', 'keyup', 'mousedown', 'mouseup',
|
|
|
|
'mousemove', 'compositionstart', 'compositionend'
|
|
|
|
] );
|
2013-09-07 09:32:05 +00:00
|
|
|
this.clipboard = [];
|
|
|
|
this.clipboardId = String( Math.random() );
|
2013-09-04 22:24:08 +00:00
|
|
|
this.renderLocks = 0;
|
2012-11-02 22:45:26 +00:00
|
|
|
this.dragging = false;
|
2013-04-15 17:54:49 +00:00
|
|
|
this.relocating = false;
|
2012-11-02 22:45:26 +00:00
|
|
|
this.selecting = false;
|
2013-11-12 11:24:12 +00:00
|
|
|
this.resizing = false;
|
2013-10-24 22:18:35 +00:00
|
|
|
this.contentBranchNodeChanged = false;
|
2013-11-01 19:45:59 +00:00
|
|
|
this.$phantoms = this.$( '<div>' );
|
|
|
|
this.$highlights = this.$( '<div>' );
|
|
|
|
this.$pasteTarget = this.$( '<div>' );
|
2012-12-07 22:58:29 +00:00
|
|
|
this.pasting = false;
|
2013-10-07 20:45:19 +00:00
|
|
|
this.pasteSpecial = false;
|
2012-12-21 18:51:20 +00:00
|
|
|
this.clickHistory = [];
|
2013-04-18 20:54:37 +00:00
|
|
|
this.focusedNode = null;
|
2013-10-01 02:57:18 +00:00
|
|
|
// This is set on entering changeModel, then unset when leaving.
|
2013-09-30 21:39:49 +00:00
|
|
|
// It is used to test whether a reflected change event is emitted.
|
|
|
|
this.newModelSelection = null;
|
2012-02-07 19:13:19 +00:00
|
|
|
|
2012-06-20 01:20:28 +00:00
|
|
|
// Events
|
2013-05-01 22:21:32 +00:00
|
|
|
this.surfaceObserver.connect(
|
2012-10-05 00:08:26 +00:00
|
|
|
this, { 'contentChange': 'onContentChange', 'selectionChange': 'onSelectionChange' }
|
|
|
|
);
|
2013-10-01 02:57:18 +00:00
|
|
|
this.model.connect( this,
|
2013-10-01 23:40:08 +00:00
|
|
|
{ 'select': 'onModelSelect', 'documentUpdate': 'onModelDocumentUpdate' }
|
|
|
|
);
|
2013-06-29 21:33:33 +00:00
|
|
|
|
2013-11-01 19:45:59 +00:00
|
|
|
$documentNode = this.documentView.getDocumentNode().$element;
|
2013-06-29 21:33:33 +00:00
|
|
|
$documentNode.on( {
|
2013-09-20 13:48:30 +00:00
|
|
|
'cut': ve.bind( this.onCut, this ),
|
Followup 5592ea26: bind native focus/blur events instead of jQuery events
In jQuery 1.8, if you focus something using jQuery, the jQuery focus
event fires before the jQuery blur event, which is wrong. If you focus
something natively, the events do fire in the correct order.
See http://jsfiddle.net/WGy9h/4/ .
Fortunately, the native events always fire in the correct order, so
listen to those instead. Normally, we're not concerned with the order,
but in ce.Surface we bind the same focus/blur handlers to a pair of two
nodes, and then if the focus moves from one to the other, we'll get
confused by the events being emitted in the wrong order.
Change-Id: Ia585b42b6deb74ba55a2d55ce1922b1e04d85e81
2013-10-03 00:54:22 +00:00
|
|
|
'copy': ve.bind( this.onCopy, this )
|
2012-10-05 00:08:26 +00:00
|
|
|
} );
|
2013-09-20 13:48:30 +00:00
|
|
|
this.$pasteTarget.on( {
|
|
|
|
'cut': ve.bind( this.onCut, this ),
|
Followup 5592ea26: bind native focus/blur events instead of jQuery events
In jQuery 1.8, if you focus something using jQuery, the jQuery focus
event fires before the jQuery blur event, which is wrong. If you focus
something natively, the events do fire in the correct order.
See http://jsfiddle.net/WGy9h/4/ .
Fortunately, the native events always fire in the correct order, so
listen to those instead. Normally, we're not concerned with the order,
but in ce.Surface we bind the same focus/blur handlers to a pair of two
nodes, and then if the focus moves from one to the other, we'll get
confused by the events being emitted in the wrong order.
Change-Id: Ia585b42b6deb74ba55a2d55ce1922b1e04d85e81
2013-10-03 00:54:22 +00:00
|
|
|
'copy': ve.bind( this.onCopy, this )
|
2013-09-20 13:48:30 +00:00
|
|
|
} );
|
Followup 5592ea26: bind native focus/blur events instead of jQuery events
In jQuery 1.8, if you focus something using jQuery, the jQuery focus
event fires before the jQuery blur event, which is wrong. If you focus
something natively, the events do fire in the correct order.
See http://jsfiddle.net/WGy9h/4/ .
Fortunately, the native events always fire in the correct order, so
listen to those instead. Normally, we're not concerned with the order,
but in ce.Surface we bind the same focus/blur handlers to a pair of two
nodes, and then if the focus moves from one to the other, we'll get
confused by the events being emitted in the wrong order.
Change-Id: Ia585b42b6deb74ba55a2d55ce1922b1e04d85e81
2013-10-03 00:54:22 +00:00
|
|
|
|
|
|
|
// blur and focus fire in the wrong order in jQuery 1.8 . Bind to the native events which do
|
|
|
|
// fire in the correct order.
|
|
|
|
$documentNode[0].addEventListener( 'focus', ve.bind( this.documentOnFocus, this ) );
|
|
|
|
$documentNode[0].addEventListener( 'blur', ve.bind( this.documentOnBlur, this ) );
|
|
|
|
// $pasteTarget is focused when selecting a FocusableNode
|
|
|
|
this.$pasteTarget[0].addEventListener( 'focus', ve.bind( this.documentOnFocus, this ) );
|
|
|
|
this.$pasteTarget[0].addEventListener( 'blur', ve.bind( this.documentOnBlur, this ) );
|
|
|
|
|
2013-09-20 13:48:30 +00:00
|
|
|
$documentNode.on( $.browser.msie ? 'beforepaste' : 'paste', ve.bind( this.onPaste, this ) );
|
2013-06-29 21:33:33 +00:00
|
|
|
$documentNode.on( 'focus', 'a', function () {
|
|
|
|
// Opera triggers 'blur' on document node before any link is
|
|
|
|
// focused and we don't want that
|
2013-08-04 21:09:56 +00:00
|
|
|
$documentNode.focus();
|
2013-06-29 21:33:33 +00:00
|
|
|
} );
|
|
|
|
|
2013-11-01 19:45:59 +00:00
|
|
|
this.$element.on( {
|
2013-04-15 17:54:49 +00:00
|
|
|
'dragover': ve.bind( this.onDocumentDragOver, this ),
|
|
|
|
'drop': ve.bind( this.onDocumentDrop, this )
|
2012-03-16 22:01:09 +00:00
|
|
|
} );
|
2013-08-21 21:00:48 +00:00
|
|
|
|
2013-09-07 00:59:42 +00:00
|
|
|
// Add listeners to the eventSequencer. They won't get called until
|
|
|
|
// eventSequencer.attach(node) has been called.
|
|
|
|
this.eventSequencer.on( {
|
|
|
|
'keydown': ve.bind( this.onDocumentKeyDown, this ),
|
|
|
|
'keyup': ve.bind( this.onDocumentKeyUp, this ),
|
|
|
|
'keypress': ve.bind( this.onDocumentKeyPress, this ),
|
|
|
|
'mousedown': ve.bind( this.onDocumentMouseDown, this ),
|
|
|
|
'mouseup': ve.bind( this.onDocumentMouseUp, this ),
|
|
|
|
'mousemove': ve.bind( this.onDocumentMouseMove, this ),
|
|
|
|
'compositionstart': ve.bind( this.onDocumentCompositionStart, this ),
|
|
|
|
'compositionend': ve.bind( this.onDocumentCompositionEnd, this )
|
|
|
|
} );
|
|
|
|
this.eventSequencer.after( {
|
|
|
|
'keypress': ve.bind( this.afterDocumentKeyPress, this )
|
|
|
|
} );
|
|
|
|
|
2012-03-01 01:28:39 +00:00
|
|
|
// Initialization
|
2013-11-01 19:45:59 +00:00
|
|
|
this.$element.addClass( 've-ce-surface' );
|
2013-01-18 21:32:15 +00:00
|
|
|
this.$phantoms.addClass( 've-ce-surface-phantoms' );
|
2013-06-05 20:59:19 +00:00
|
|
|
this.$highlights.addClass( 've-ce-surface-highlights' );
|
2013-08-28 23:20:47 +00:00
|
|
|
this.$pasteTarget.addClass( 've-ce-surface-paste' ).prop( 'contentEditable', 'true' );
|
2013-05-15 19:28:56 +00:00
|
|
|
|
|
|
|
// Add elements to the DOM
|
2013-11-01 19:45:59 +00:00
|
|
|
this.$element.append( this.documentView.getDocumentNode().$element, this.$pasteTarget );
|
2013-06-27 18:24:26 +00:00
|
|
|
this.surface.$localOverlayBlockers.append( this.$phantoms, this.$highlights );
|
2012-03-01 01:28:39 +00:00
|
|
|
};
|
2012-02-08 06:28:38 +00:00
|
|
|
|
Object management: Object create/inherit/clone utilities
* For the most common case:
- replace ve.extendClass with ve.inheritClass (chose slightly
different names to detect usage of the old/new one, and I
like 'inherit' better).
- move it up to below the constructor, see doc block for why.
* Cases where more than 2 arguments were passed to
ve.extendClass are handled differently depending on the case.
In case of a longer inheritance tree, the other arguments
could be omitted (like in "ve.ce.FooBar, ve.FooBar,
ve.Bar". ve.ce.FooBar only needs to inherit from ve.FooBar,
because ve.ce.FooBar inherits from ve.Bar).
In the case of where it previously had two mixins with
ve.extendClass(), either one becomes inheritClass and one
a mixin, both to mixinClass().
No visible changes should come from this commit as the
instances still all have the same visible properties in the
end. No more or less than before.
* Misc.:
- Be consistent in calling parent constructors in the
same order as the inheritance.
- Add missing @extends and @param documentation.
- Replace invalid {Integer} type hint with {Number}.
- Consistent doc comments order:
@class, @abstract, @constructor, @extends, @params.
- Fix indentation errors
A fairly common mistake was a superfluous space before the
identifier on the assignment line directly below the
documentation comment.
$ ack "^ [^*]" --js modules/ve
- Typo "Inhertiance" -> "Inheritance".
- Replacing the other confusing comment "Inheritance" (inside
the constructor) with "Parent constructor".
- Add missing @abstract for ve.ui.Tool.
- Corrected ve.FormatDropdownTool to ve.ui.FormatDropdownTool.js
- Add function names to all @constructor functions. Now that we
have inheritance it is important and useful to have these
functions not be anonymous.
Example of debug shot: http://cl.ly/image/1j3c160w3D45
Makes the difference between
< documentNode;
> ve_dm_DocumentNode
...
: ve_dm_BranchNode
...
: ve_dm_Node
...
: ve_dm_Node
...
: Object
...
without names (current situation):
< documentNode;
> Object
...
: Object
...
: Object
...
: Object
...
: Object
...
though before this commit, it really looks like this
(flattened since ve.extendClass really did a mixin):
< documentNode;
> Object
...
...
...
Pattern in Sublime (case-sensitive) to find nameless
constructor functions:
"^ve\..*\.([A-Z])([^\.]+) = function \("
Change-Id: Iab763954fb8cf375900d7a9a92dec1c755d5407e
2012-09-05 06:07:47 +00:00
|
|
|
/* Inheritance */
|
|
|
|
|
2013-10-09 20:09:59 +00:00
|
|
|
OO.inheritClass( ve.ce.Surface, OO.ui.Element );
|
2013-05-14 23:45:42 +00:00
|
|
|
|
2013-10-15 11:58:04 +00:00
|
|
|
OO.mixinClass( ve.ce.Surface, OO.EventEmitter );
|
Object management: Object create/inherit/clone utilities
* For the most common case:
- replace ve.extendClass with ve.inheritClass (chose slightly
different names to detect usage of the old/new one, and I
like 'inherit' better).
- move it up to below the constructor, see doc block for why.
* Cases where more than 2 arguments were passed to
ve.extendClass are handled differently depending on the case.
In case of a longer inheritance tree, the other arguments
could be omitted (like in "ve.ce.FooBar, ve.FooBar,
ve.Bar". ve.ce.FooBar only needs to inherit from ve.FooBar,
because ve.ce.FooBar inherits from ve.Bar).
In the case of where it previously had two mixins with
ve.extendClass(), either one becomes inheritClass and one
a mixin, both to mixinClass().
No visible changes should come from this commit as the
instances still all have the same visible properties in the
end. No more or less than before.
* Misc.:
- Be consistent in calling parent constructors in the
same order as the inheritance.
- Add missing @extends and @param documentation.
- Replace invalid {Integer} type hint with {Number}.
- Consistent doc comments order:
@class, @abstract, @constructor, @extends, @params.
- Fix indentation errors
A fairly common mistake was a superfluous space before the
identifier on the assignment line directly below the
documentation comment.
$ ack "^ [^*]" --js modules/ve
- Typo "Inhertiance" -> "Inheritance".
- Replacing the other confusing comment "Inheritance" (inside
the constructor) with "Parent constructor".
- Add missing @abstract for ve.ui.Tool.
- Corrected ve.FormatDropdownTool to ve.ui.FormatDropdownTool.js
- Add function names to all @constructor functions. Now that we
have inheritance it is important and useful to have these
functions not be anonymous.
Example of debug shot: http://cl.ly/image/1j3c160w3D45
Makes the difference between
< documentNode;
> ve_dm_DocumentNode
...
: ve_dm_BranchNode
...
: ve_dm_Node
...
: ve_dm_Node
...
: Object
...
without names (current situation):
< documentNode;
> Object
...
: Object
...
: Object
...
: Object
...
: Object
...
though before this commit, it really looks like this
(flattened since ve.extendClass really did a mixin):
< documentNode;
> Object
...
...
...
Pattern in Sublime (case-sensitive) to find nameless
constructor functions:
"^ve\..*\.([A-Z])([^\.]+) = function \("
Change-Id: Iab763954fb8cf375900d7a9a92dec1c755d5407e
2012-09-05 06:07:47 +00:00
|
|
|
|
2013-03-20 07:09:43 +00:00
|
|
|
/* Events */
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @event selectionStart
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @event selectionEnd
|
|
|
|
*/
|
|
|
|
|
2013-04-15 17:54:49 +00:00
|
|
|
/**
|
|
|
|
* @event relocationStart
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @event relocationEnd
|
|
|
|
*/
|
|
|
|
|
2013-11-27 21:30:25 +00:00
|
|
|
/**
|
|
|
|
* @event focus
|
|
|
|
* Note that it's possible for a focus event to occur immediately after a blur event, if the focus
|
|
|
|
* moves to or from a FocusableNode. In this case the surface doesn't lose focus conceptually, but
|
|
|
|
* a pair of blur-focus events is emitted anyway.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @event blur
|
|
|
|
* Note that it's possible for a focus event to occur immediately after a blur event, if the focus
|
|
|
|
* moves to or from a FocusableNode. In this case the surface doesn't lose focus conceptually, but
|
|
|
|
* a pair of blur-focus events is emitted anyway.
|
|
|
|
*/
|
|
|
|
|
2013-09-07 09:32:05 +00:00
|
|
|
/* Static methods */
|
|
|
|
|
|
|
|
/**
|
|
|
|
* When pasting, browsers normalize HTML to varying degrees.
|
|
|
|
* This hash creates a comparable string for validating clipboard contents.
|
|
|
|
*
|
2013-09-20 14:32:45 +00:00
|
|
|
* @param {jQuery} $elements Clipboard HTML elements
|
2013-09-07 09:32:05 +00:00
|
|
|
* @returns {string} Hash
|
|
|
|
*/
|
2013-09-20 14:32:45 +00:00
|
|
|
ve.ce.Surface.static.getClipboardHash = function ( $elements ) {
|
|
|
|
var hash = '';
|
|
|
|
// Collect text contents, or just node name for content-less nodes.
|
|
|
|
$elements.each( function () {
|
|
|
|
hash += this.textContent || '<' + this.nodeName + '>';
|
|
|
|
} );
|
|
|
|
// Whitespace may be added/removed, so strip it all
|
|
|
|
return hash.replace( /\s/gm, '' );
|
2013-09-07 09:32:05 +00:00
|
|
|
};
|
|
|
|
|
The Great ve.ui.Surface refactor of 2013
Prologue:
Farewell ve.Editor my good chap… Oh, hey there HTML frames - I didn't
see you there! In a world where iframes are outlaws, and symbols like
document and window are global, there were more than a few assumptions
about which document or window was being used. But fear not - for this
commit (probably) tracks them all down, leaving a trail of
iframe-compatible awesomeness in its wake. With the great ve.ui.Surface
now able to be used inside of iframes, let the reference editing
commence. But there, lurking in the darkness is a DM issue so fierce it
may take Roan and/or Ed up to 3 whole hours to sort it out.
Note to Roan and/or Ed:
Editing references seems to work fine, but when saving the page there
are "no changes" which is a reasonable indication to the contrary.
Objectives:
* Make it possible to have multiple surfaces be instantiated, get along
nicely, and be embedded inside of iframes if needed.
* Make reference content editable within a dialog
Approach:
* Move what's left of ve.Editor to ve.ui.Surface and essentially
obliterate all use of it
* Make even more stuff inherit from ve.Element (long live this.$$)
* Use the correct document or window anywhere it was being assumed to be
the top level one
* Resolve stacking order issues by removing the excessive use of z-index
and introducing global and local overlay elements for each editor
* Add a surface to the reference dialog, load up the reference contents
and save them back on apply
* Actually destroy what we create in ce and ui surfaces
* Add recursive frame offset calculation method to ve.Element
* Moved ve.ce.Surface's getSelectionRect method to the prototype
Bonus:
* Move ve.ce.DocumentNode.css contents to ve.ce.Node.css (not sure why it
was separate in the first place, but I'm likely the one to blame)
* Fix blatant lies in documentation
* Whitespace cleanup here and there
* Get rid of ve.ui.Window overlays - not used or needed
Change-Id: Iede83e7d24f7cb249b6ba3dc45d770445b862e08
2013-05-20 22:45:50 +00:00
|
|
|
/* Methods */
|
|
|
|
|
2013-03-26 06:10:17 +00:00
|
|
|
/**
|
|
|
|
* Get the coordinates of the selection anchor.
|
|
|
|
*
|
|
|
|
* @method
|
2013-10-08 09:34:41 +00:00
|
|
|
* @returns {Object|null} { 'start': { 'x': ..., 'y': ... }, 'end': { 'x': ..., 'y': ... } }
|
2013-03-26 06:10:17 +00:00
|
|
|
*/
|
The Great ve.ui.Surface refactor of 2013
Prologue:
Farewell ve.Editor my good chap… Oh, hey there HTML frames - I didn't
see you there! In a world where iframes are outlaws, and symbols like
document and window are global, there were more than a few assumptions
about which document or window was being used. But fear not - for this
commit (probably) tracks them all down, leaving a trail of
iframe-compatible awesomeness in its wake. With the great ve.ui.Surface
now able to be used inside of iframes, let the reference editing
commence. But there, lurking in the darkness is a DM issue so fierce it
may take Roan and/or Ed up to 3 whole hours to sort it out.
Note to Roan and/or Ed:
Editing references seems to work fine, but when saving the page there
are "no changes" which is a reasonable indication to the contrary.
Objectives:
* Make it possible to have multiple surfaces be instantiated, get along
nicely, and be embedded inside of iframes if needed.
* Make reference content editable within a dialog
Approach:
* Move what's left of ve.Editor to ve.ui.Surface and essentially
obliterate all use of it
* Make even more stuff inherit from ve.Element (long live this.$$)
* Use the correct document or window anywhere it was being assumed to be
the top level one
* Resolve stacking order issues by removing the excessive use of z-index
and introducing global and local overlay elements for each editor
* Add a surface to the reference dialog, load up the reference contents
and save them back on apply
* Actually destroy what we create in ce and ui surfaces
* Add recursive frame offset calculation method to ve.Element
* Moved ve.ce.Surface's getSelectionRect method to the prototype
Bonus:
* Move ve.ce.DocumentNode.css contents to ve.ce.Node.css (not sure why it
was separate in the first place, but I'm likely the one to blame)
* Fix blatant lies in documentation
* Whitespace cleanup here and there
* Get rid of ve.ui.Window overlays - not used or needed
Change-Id: Iede83e7d24f7cb249b6ba3dc45d770445b862e08
2013-05-20 22:45:50 +00:00
|
|
|
ve.ce.Surface.prototype.getSelectionRect = function () {
|
2013-06-05 20:59:19 +00:00
|
|
|
var sel, rect, $span, lineHeight, startRange, startOffset, endRange, endOffset, focusedOffset;
|
|
|
|
|
|
|
|
if ( this.focusedNode ) {
|
2013-11-01 19:45:59 +00:00
|
|
|
focusedOffset = this.focusedNode.$element.offset();
|
2013-06-05 20:59:19 +00:00
|
|
|
return {
|
|
|
|
'start': {
|
|
|
|
'x': focusedOffset.left,
|
|
|
|
'y': focusedOffset.top
|
|
|
|
},
|
|
|
|
'end': {
|
2013-11-01 19:45:59 +00:00
|
|
|
'x': focusedOffset.left + this.focusedNode.$element.width(),
|
|
|
|
'y': focusedOffset.top + this.focusedNode.$element.height()
|
2013-06-05 20:59:19 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
2013-04-27 16:24:03 +00:00
|
|
|
|
2013-03-28 21:50:43 +00:00
|
|
|
if ( !rangy.initialized ) {
|
|
|
|
rangy.init();
|
|
|
|
}
|
2013-04-27 16:24:03 +00:00
|
|
|
|
2013-06-05 20:59:19 +00:00
|
|
|
sel = rangy.getSelection( this.getElementDocument() );
|
2013-04-27 16:24:03 +00:00
|
|
|
|
|
|
|
// We can't do anything if there's no selection
|
|
|
|
if ( sel.rangeCount === 0 ) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
rect = sel.getBoundingDocumentRect();
|
|
|
|
|
|
|
|
// Sometimes the selection will have invalid bounding rect information, which presents as all
|
|
|
|
// rectangle dimensions being 0 which causes #getStartDocumentPos and #getEndDocumentPos to
|
|
|
|
// throw exceptions
|
|
|
|
if ( rect.top === 0 || rect.bottom === 0 || rect.left === 0 || rect.right === 0 ) {
|
|
|
|
// Calculate starting range position
|
|
|
|
startRange = sel.getRangeAt( 0 );
|
2013-11-01 19:45:59 +00:00
|
|
|
$span = this.$( '<span>|</span>', startRange.startContainer.ownerDocument );
|
2013-04-27 16:24:03 +00:00
|
|
|
startRange.insertNode( $span[0] );
|
|
|
|
startOffset = $span.offset();
|
|
|
|
$span.detach();
|
|
|
|
|
|
|
|
// Calculate ending range position
|
|
|
|
endRange = startRange.cloneRange();
|
|
|
|
endRange.collapse( false );
|
|
|
|
endRange.insertNode( $span[0] );
|
|
|
|
endOffset = $span.offset();
|
The Great ve.ui.Surface refactor of 2013
Prologue:
Farewell ve.Editor my good chap… Oh, hey there HTML frames - I didn't
see you there! In a world where iframes are outlaws, and symbols like
document and window are global, there were more than a few assumptions
about which document or window was being used. But fear not - for this
commit (probably) tracks them all down, leaving a trail of
iframe-compatible awesomeness in its wake. With the great ve.ui.Surface
now able to be used inside of iframes, let the reference editing
commence. But there, lurking in the darkness is a DM issue so fierce it
may take Roan and/or Ed up to 3 whole hours to sort it out.
Note to Roan and/or Ed:
Editing references seems to work fine, but when saving the page there
are "no changes" which is a reasonable indication to the contrary.
Objectives:
* Make it possible to have multiple surfaces be instantiated, get along
nicely, and be embedded inside of iframes if needed.
* Make reference content editable within a dialog
Approach:
* Move what's left of ve.Editor to ve.ui.Surface and essentially
obliterate all use of it
* Make even more stuff inherit from ve.Element (long live this.$$)
* Use the correct document or window anywhere it was being assumed to be
the top level one
* Resolve stacking order issues by removing the excessive use of z-index
and introducing global and local overlay elements for each editor
* Add a surface to the reference dialog, load up the reference contents
and save them back on apply
* Actually destroy what we create in ce and ui surfaces
* Add recursive frame offset calculation method to ve.Element
* Moved ve.ce.Surface's getSelectionRect method to the prototype
Bonus:
* Move ve.ce.DocumentNode.css contents to ve.ce.Node.css (not sure why it
was separate in the first place, but I'm likely the one to blame)
* Fix blatant lies in documentation
* Whitespace cleanup here and there
* Get rid of ve.ui.Window overlays - not used or needed
Change-Id: Iede83e7d24f7cb249b6ba3dc45d770445b862e08
2013-05-20 22:45:50 +00:00
|
|
|
lineHeight = $span.height();
|
2013-04-27 16:24:03 +00:00
|
|
|
$span.detach();
|
|
|
|
|
|
|
|
// Restore the selection
|
|
|
|
startRange.refresh();
|
|
|
|
|
|
|
|
// Return the selection bounding rectangle
|
|
|
|
return {
|
|
|
|
'start': {
|
2013-05-06 20:21:54 +00:00
|
|
|
'x': startOffset.left,
|
|
|
|
'y': startOffset.top
|
2013-04-27 16:24:03 +00:00
|
|
|
},
|
|
|
|
'end': {
|
2013-05-06 20:21:54 +00:00
|
|
|
'x': endOffset.left,
|
2013-04-27 16:24:03 +00:00
|
|
|
// Adjust the vertical position by the line-height to get the bottom dimension
|
2013-05-06 20:21:54 +00:00
|
|
|
'y': endOffset.top + lineHeight
|
2013-04-27 16:24:03 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
} else {
|
|
|
|
return {
|
2013-05-15 23:31:02 +00:00
|
|
|
'start': sel.getStartDocumentPos(),
|
|
|
|
'end': sel.getEndDocumentPos()
|
2013-04-27 16:24:03 +00:00
|
|
|
};
|
|
|
|
}
|
2013-03-26 06:10:17 +00:00
|
|
|
};
|
|
|
|
|
2013-01-16 21:51:05 +00:00
|
|
|
/*! Initialization */
|
|
|
|
|
2013-05-14 23:45:42 +00:00
|
|
|
/**
|
|
|
|
* Initialize surface.
|
|
|
|
*
|
|
|
|
* This should be called after the surface has been attached to the DOM.
|
|
|
|
*
|
|
|
|
* @method
|
|
|
|
*/
|
|
|
|
ve.ce.Surface.prototype.initialize = function () {
|
|
|
|
if ( !rangy.initialized ) {
|
|
|
|
rangy.init();
|
|
|
|
}
|
|
|
|
this.documentView.getDocumentNode().setLive( true );
|
|
|
|
// Turn off native object editing. This must be tried after the surface has been added to DOM.
|
|
|
|
try {
|
The Great ve.ui.Surface refactor of 2013
Prologue:
Farewell ve.Editor my good chap… Oh, hey there HTML frames - I didn't
see you there! In a world where iframes are outlaws, and symbols like
document and window are global, there were more than a few assumptions
about which document or window was being used. But fear not - for this
commit (probably) tracks them all down, leaving a trail of
iframe-compatible awesomeness in its wake. With the great ve.ui.Surface
now able to be used inside of iframes, let the reference editing
commence. But there, lurking in the darkness is a DM issue so fierce it
may take Roan and/or Ed up to 3 whole hours to sort it out.
Note to Roan and/or Ed:
Editing references seems to work fine, but when saving the page there
are "no changes" which is a reasonable indication to the contrary.
Objectives:
* Make it possible to have multiple surfaces be instantiated, get along
nicely, and be embedded inside of iframes if needed.
* Make reference content editable within a dialog
Approach:
* Move what's left of ve.Editor to ve.ui.Surface and essentially
obliterate all use of it
* Make even more stuff inherit from ve.Element (long live this.$$)
* Use the correct document or window anywhere it was being assumed to be
the top level one
* Resolve stacking order issues by removing the excessive use of z-index
and introducing global and local overlay elements for each editor
* Add a surface to the reference dialog, load up the reference contents
and save them back on apply
* Actually destroy what we create in ce and ui surfaces
* Add recursive frame offset calculation method to ve.Element
* Moved ve.ce.Surface's getSelectionRect method to the prototype
Bonus:
* Move ve.ce.DocumentNode.css contents to ve.ce.Node.css (not sure why it
was separate in the first place, but I'm likely the one to blame)
* Fix blatant lies in documentation
* Whitespace cleanup here and there
* Get rid of ve.ui.Window overlays - not used or needed
Change-Id: Iede83e7d24f7cb249b6ba3dc45d770445b862e08
2013-05-20 22:45:50 +00:00
|
|
|
this.$document[0].execCommand( 'enableObjectResizing', false, false );
|
|
|
|
this.$document[0].execCommand( 'enableInlineTableEditing', false, false );
|
2013-05-14 23:45:42 +00:00
|
|
|
} catch ( e ) { /* Silently ignore */ }
|
|
|
|
};
|
|
|
|
|
2012-12-03 21:45:38 +00:00
|
|
|
/**
|
2013-01-16 21:51:05 +00:00
|
|
|
* Enable editing.
|
2012-12-03 21:45:38 +00:00
|
|
|
*
|
|
|
|
* @method
|
|
|
|
*/
|
2013-01-16 21:51:05 +00:00
|
|
|
ve.ce.Surface.prototype.enable = function () {
|
|
|
|
this.documentView.getDocumentNode().enable();
|
2012-12-03 21:45:38 +00:00
|
|
|
};
|
|
|
|
|
2012-12-12 00:28:39 +00:00
|
|
|
/**
|
2013-01-15 23:38:49 +00:00
|
|
|
* Disable editing.
|
2012-12-12 00:28:39 +00:00
|
|
|
*
|
|
|
|
* @method
|
|
|
|
*/
|
|
|
|
ve.ce.Surface.prototype.disable = function () {
|
|
|
|
this.documentView.getDocumentNode().disable();
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
2013-01-16 21:51:05 +00:00
|
|
|
* Destroy the surface, removing all DOM elements.
|
2012-12-12 00:28:39 +00:00
|
|
|
*
|
|
|
|
* @method
|
|
|
|
*/
|
2013-01-16 21:51:05 +00:00
|
|
|
ve.ce.Surface.prototype.destroy = function () {
|
2013-10-06 12:59:42 +00:00
|
|
|
this.surfaceObserver.detach();
|
2013-05-22 10:52:53 +00:00
|
|
|
this.documentView.getDocumentNode().setLive( false );
|
2013-11-01 19:45:59 +00:00
|
|
|
this.$element.remove();
|
The Great ve.ui.Surface refactor of 2013
Prologue:
Farewell ve.Editor my good chap… Oh, hey there HTML frames - I didn't
see you there! In a world where iframes are outlaws, and symbols like
document and window are global, there were more than a few assumptions
about which document or window was being used. But fear not - for this
commit (probably) tracks them all down, leaving a trail of
iframe-compatible awesomeness in its wake. With the great ve.ui.Surface
now able to be used inside of iframes, let the reference editing
commence. But there, lurking in the darkness is a DM issue so fierce it
may take Roan and/or Ed up to 3 whole hours to sort it out.
Note to Roan and/or Ed:
Editing references seems to work fine, but when saving the page there
are "no changes" which is a reasonable indication to the contrary.
Objectives:
* Make it possible to have multiple surfaces be instantiated, get along
nicely, and be embedded inside of iframes if needed.
* Make reference content editable within a dialog
Approach:
* Move what's left of ve.Editor to ve.ui.Surface and essentially
obliterate all use of it
* Make even more stuff inherit from ve.Element (long live this.$$)
* Use the correct document or window anywhere it was being assumed to be
the top level one
* Resolve stacking order issues by removing the excessive use of z-index
and introducing global and local overlay elements for each editor
* Add a surface to the reference dialog, load up the reference contents
and save them back on apply
* Actually destroy what we create in ce and ui surfaces
* Add recursive frame offset calculation method to ve.Element
* Moved ve.ce.Surface's getSelectionRect method to the prototype
Bonus:
* Move ve.ce.DocumentNode.css contents to ve.ce.Node.css (not sure why it
was separate in the first place, but I'm likely the one to blame)
* Fix blatant lies in documentation
* Whitespace cleanup here and there
* Get rid of ve.ui.Window overlays - not used or needed
Change-Id: Iede83e7d24f7cb249b6ba3dc45d770445b862e08
2013-05-20 22:45:50 +00:00
|
|
|
this.$phantoms.remove();
|
2012-10-11 18:31:28 +00:00
|
|
|
};
|
|
|
|
|
2013-06-21 11:43:46 +00:00
|
|
|
/**
|
2013-11-06 06:13:12 +00:00
|
|
|
* Give focus to the surface, reapplying the model selection.
|
2013-06-21 11:43:46 +00:00
|
|
|
*
|
|
|
|
* This is used when switching between surfaces, e.g. when closing a dialog window.
|
2013-11-06 06:13:12 +00:00
|
|
|
*
|
|
|
|
* If the surface is already focused, this does nothing. In particular, the selection won't be
|
|
|
|
* reapplied.
|
2013-06-21 11:43:46 +00:00
|
|
|
*/
|
|
|
|
ve.ce.Surface.prototype.focus = function () {
|
2013-12-09 22:31:08 +00:00
|
|
|
// Focus the documentNode for text selections, or the pasteTarget for focusedNode selections
|
|
|
|
if ( this.focusedNode ) {
|
|
|
|
this.$pasteTarget[0].focus();
|
|
|
|
} else {
|
|
|
|
this.documentView.getDocumentNode().$element[0].focus();
|
|
|
|
}
|
2013-11-06 06:13:12 +00:00
|
|
|
// documentOnFocus takes care of the rest
|
2013-06-21 11:43:46 +00:00
|
|
|
};
|
|
|
|
|
2013-01-16 21:51:05 +00:00
|
|
|
/*! Native Browser Events */
|
2012-10-01 20:05:06 +00:00
|
|
|
|
Make use of new jshint options
* Restricting "camelcase":
No changes, we were passing all of these already
* Explicitly unrestricting "forin" and "plusplus"
These are off by default in node-jshint, but some distro of jshint
and editors that use their own wrapper around jshint instead of
node-jshint (Eclipse?) may have different defaults. Therefor
setting them to false explicitly. This also serves as a reminder
for the future so we'll always know we don't pass that, in case
we would want to change that.
* Fix order ("quotemark" before "regexp")
* Restricting "unused"
We're not passing all of this, which is why I've set it to false
for now. But I did put it in .jshintrc as placeholder.
I've fixed most of them, there's some left where there is no clean
solution.
* While at it fix a few issues:
- Unused variables ($target, $window)
- Bad practices (using jQuery context for find instead of creation)
- Redundant /*global */ comments
- Parameters that are not used and don't have documentation either
- Lines longer than 100 chars @ 4 spaces/tab
* Note:
- ve.ce.Surface.prototype.onChange takes two arguments but never
uses the former. And even the second one can be null/undefined.
Aside from that, the .change() function emits
another event for the transaction already. Looks like this
should be refactored a bit, two more separated events probably
or one that is actually used better.
- Also cleaned up a lot of comments, some of which were missing,
others were incorrect
- Reworked the contentChange event so we are no longer using the
word new as an object key; expanded a complex object into multiple
arguments being passed through the event to make it easier to work
with and document
Change-Id: I8490815a508c6c379d5f9a743bb4aefd14576aa6
2012-08-07 06:02:18 +00:00
|
|
|
/**
|
2013-01-15 23:38:49 +00:00
|
|
|
* Handle document focus events.
|
Make use of new jshint options
* Restricting "camelcase":
No changes, we were passing all of these already
* Explicitly unrestricting "forin" and "plusplus"
These are off by default in node-jshint, but some distro of jshint
and editors that use their own wrapper around jshint instead of
node-jshint (Eclipse?) may have different defaults. Therefor
setting them to false explicitly. This also serves as a reminder
for the future so we'll always know we don't pass that, in case
we would want to change that.
* Fix order ("quotemark" before "regexp")
* Restricting "unused"
We're not passing all of this, which is why I've set it to false
for now. But I did put it in .jshintrc as placeholder.
I've fixed most of them, there's some left where there is no clean
solution.
* While at it fix a few issues:
- Unused variables ($target, $window)
- Bad practices (using jQuery context for find instead of creation)
- Redundant /*global */ comments
- Parameters that are not used and don't have documentation either
- Lines longer than 100 chars @ 4 spaces/tab
* Note:
- ve.ce.Surface.prototype.onChange takes two arguments but never
uses the former. And even the second one can be null/undefined.
Aside from that, the .change() function emits
another event for the transaction already. Looks like this
should be refactored a bit, two more separated events probably
or one that is actually used better.
- Also cleaned up a lot of comments, some of which were missing,
others were incorrect
- Reworked the contentChange event so we are no longer using the
word new as an object key; expanded a complex object into multiple
arguments being passed through the event to make it easier to work
with and document
Change-Id: I8490815a508c6c379d5f9a743bb4aefd14576aa6
2012-08-07 06:02:18 +00:00
|
|
|
*
|
|
|
|
* @method
|
Followup 5592ea26: bind native focus/blur events instead of jQuery events
In jQuery 1.8, if you focus something using jQuery, the jQuery focus
event fires before the jQuery blur event, which is wrong. If you focus
something natively, the events do fire in the correct order.
See http://jsfiddle.net/WGy9h/4/ .
Fortunately, the native events always fire in the correct order, so
listen to those instead. Normally, we're not concerned with the order,
but in ce.Surface we bind the same focus/blur handlers to a pair of two
nodes, and then if the focus moves from one to the other, we'll get
confused by the events being emitted in the wrong order.
Change-Id: Ia585b42b6deb74ba55a2d55ce1922b1e04d85e81
2013-10-03 00:54:22 +00:00
|
|
|
* @param {Event} e Focus event (native event, NOT a jQuery event!)
|
2013-11-27 21:30:25 +00:00
|
|
|
* @fires focus
|
Make use of new jshint options
* Restricting "camelcase":
No changes, we were passing all of these already
* Explicitly unrestricting "forin" and "plusplus"
These are off by default in node-jshint, but some distro of jshint
and editors that use their own wrapper around jshint instead of
node-jshint (Eclipse?) may have different defaults. Therefor
setting them to false explicitly. This also serves as a reminder
for the future so we'll always know we don't pass that, in case
we would want to change that.
* Fix order ("quotemark" before "regexp")
* Restricting "unused"
We're not passing all of this, which is why I've set it to false
for now. But I did put it in .jshintrc as placeholder.
I've fixed most of them, there's some left where there is no clean
solution.
* While at it fix a few issues:
- Unused variables ($target, $window)
- Bad practices (using jQuery context for find instead of creation)
- Redundant /*global */ comments
- Parameters that are not used and don't have documentation either
- Lines longer than 100 chars @ 4 spaces/tab
* Note:
- ve.ce.Surface.prototype.onChange takes two arguments but never
uses the former. And even the second one can be null/undefined.
Aside from that, the .change() function emits
another event for the transaction already. Looks like this
should be refactored a bit, two more separated events probably
or one that is actually used better.
- Also cleaned up a lot of comments, some of which were missing,
others were incorrect
- Reworked the contentChange event so we are no longer using the
word new as an object key; expanded a complex object into multiple
arguments being passed through the event to make it easier to work
with and document
Change-Id: I8490815a508c6c379d5f9a743bb4aefd14576aa6
2012-08-07 06:02:18 +00:00
|
|
|
*/
|
2013-11-06 06:13:12 +00:00
|
|
|
ve.ce.Surface.prototype.documentOnFocus = function ( e ) {
|
2013-12-09 22:31:08 +00:00
|
|
|
if ( e.target === this.documentView.getDocumentNode().$element[0] && !this.focusedNode ) {
|
2013-11-06 06:13:12 +00:00
|
|
|
// The document node was focused (as opposed to the paste target)
|
|
|
|
// Restore the selection
|
|
|
|
this.onModelSelect( this.surface.getModel().getSelection() );
|
|
|
|
}
|
2013-11-01 19:45:59 +00:00
|
|
|
this.eventSequencer.attach( this.$element );
|
2013-09-07 01:03:10 +00:00
|
|
|
this.surfaceObserver.startTimerLoop();
|
2013-11-27 21:30:25 +00:00
|
|
|
this.emit( 'focus' );
|
2012-04-26 21:49:12 +00:00
|
|
|
};
|
|
|
|
|
2013-01-15 23:38:49 +00:00
|
|
|
/**
|
2013-01-16 21:51:05 +00:00
|
|
|
* Handle document blur events.
|
Make use of new jshint options
* Restricting "camelcase":
No changes, we were passing all of these already
* Explicitly unrestricting "forin" and "plusplus"
These are off by default in node-jshint, but some distro of jshint
and editors that use their own wrapper around jshint instead of
node-jshint (Eclipse?) may have different defaults. Therefor
setting them to false explicitly. This also serves as a reminder
for the future so we'll always know we don't pass that, in case
we would want to change that.
* Fix order ("quotemark" before "regexp")
* Restricting "unused"
We're not passing all of this, which is why I've set it to false
for now. But I did put it in .jshintrc as placeholder.
I've fixed most of them, there's some left where there is no clean
solution.
* While at it fix a few issues:
- Unused variables ($target, $window)
- Bad practices (using jQuery context for find instead of creation)
- Redundant /*global */ comments
- Parameters that are not used and don't have documentation either
- Lines longer than 100 chars @ 4 spaces/tab
* Note:
- ve.ce.Surface.prototype.onChange takes two arguments but never
uses the former. And even the second one can be null/undefined.
Aside from that, the .change() function emits
another event for the transaction already. Looks like this
should be refactored a bit, two more separated events probably
or one that is actually used better.
- Also cleaned up a lot of comments, some of which were missing,
others were incorrect
- Reworked the contentChange event so we are no longer using the
word new as an object key; expanded a complex object into multiple
arguments being passed through the event to make it easier to work
with and document
Change-Id: I8490815a508c6c379d5f9a743bb4aefd14576aa6
2012-08-07 06:02:18 +00:00
|
|
|
*
|
|
|
|
* @method
|
Followup 5592ea26: bind native focus/blur events instead of jQuery events
In jQuery 1.8, if you focus something using jQuery, the jQuery focus
event fires before the jQuery blur event, which is wrong. If you focus
something natively, the events do fire in the correct order.
See http://jsfiddle.net/WGy9h/4/ .
Fortunately, the native events always fire in the correct order, so
listen to those instead. Normally, we're not concerned with the order,
but in ce.Surface we bind the same focus/blur handlers to a pair of two
nodes, and then if the focus moves from one to the other, we'll get
confused by the events being emitted in the wrong order.
Change-Id: Ia585b42b6deb74ba55a2d55ce1922b1e04d85e81
2013-10-03 00:54:22 +00:00
|
|
|
* @param {Event} e Blur event (native event, NOT a jQuery event!)
|
2013-11-27 21:30:25 +00:00
|
|
|
* @fires blur
|
Make use of new jshint options
* Restricting "camelcase":
No changes, we were passing all of these already
* Explicitly unrestricting "forin" and "plusplus"
These are off by default in node-jshint, but some distro of jshint
and editors that use their own wrapper around jshint instead of
node-jshint (Eclipse?) may have different defaults. Therefor
setting them to false explicitly. This also serves as a reminder
for the future so we'll always know we don't pass that, in case
we would want to change that.
* Fix order ("quotemark" before "regexp")
* Restricting "unused"
We're not passing all of this, which is why I've set it to false
for now. But I did put it in .jshintrc as placeholder.
I've fixed most of them, there's some left where there is no clean
solution.
* While at it fix a few issues:
- Unused variables ($target, $window)
- Bad practices (using jQuery context for find instead of creation)
- Redundant /*global */ comments
- Parameters that are not used and don't have documentation either
- Lines longer than 100 chars @ 4 spaces/tab
* Note:
- ve.ce.Surface.prototype.onChange takes two arguments but never
uses the former. And even the second one can be null/undefined.
Aside from that, the .change() function emits
another event for the transaction already. Looks like this
should be refactored a bit, two more separated events probably
or one that is actually used better.
- Also cleaned up a lot of comments, some of which were missing,
others were incorrect
- Reworked the contentChange event so we are no longer using the
word new as an object key; expanded a complex object into multiple
arguments being passed through the event to make it easier to work
with and document
Change-Id: I8490815a508c6c379d5f9a743bb4aefd14576aa6
2012-08-07 06:02:18 +00:00
|
|
|
*/
|
Kranitor #1: On-boarding
'''Kranitor commits''' are commits by Krinkle with his janitor hat on.
Must never contain functional changes mixed with miscellaneous changes.
.gitignore:
* Add .DS_Store to the ignore list so that browsing the directories
on Mac OS X, will not add these files to the list of untracked
files.
* Fix missing newline at end of file
.jshintrc
* raises -> throws
* +module (QUnit.module)
* remove 'Node' (as of node-jshint 1.7.2 this is now part of
'browser:true', as it should be)
Authors:
* Adding myself
MWExtension/VisualEditor.php
* Fix default value of wgVisualEditorParsoidURL to not
point to the experimental instance in WMF Labs.
Issues:
* ve.ce.TextNode:
- Fix TODO: Don't perform a useless clone of an already-jQuerified object.
- Use .html() to set html content instead of encapsulating between
two strings. This is slightly faster but more importantly safer,
and prevents situations where the resulting jQuery collection
actually contains 2 elements instead of 1, thus messing up
what .contents() is iterating over.
* ve.ce.Document.test.js
- Fix: ReferenceError: assert is not defined
* ve.dm.Document.test.js
- Fix: ReferenceError: assert is not defined
* ve.dm.Transaction.test.js
- Fix: ReferenceError: assert is not defined
* ve.dm.TransactionProcessor.test.js
- Fix: ReferenceError: assert is not defined
* ext.visualEditor.viewPageTarget
- Missing dependency on 'mediawiki.Title'
Code conventions / Misc cleanup
* Various JSHint warnings.
* Whitespace
* jQuery(): Use '<tag>' for element creation,
use '<valid><xml/></valid>' for parsing
* Use the default operator instead of ternary when the condition and
first value are the same.
x = foo ? foo : bar; -> x = foo || bar;
Because contrary to some programming language (PHP...), in JS the
default operator does not enforce a boolean result but returns the
original value, hence it being called the 'default' operator, as
opposed to the 'or' operator.
* No need to call addClass() twice, it takes a space-separated list
(jQuery splits by space and adds if needed)
* Use .on( event[, selector], fn ) instead of the deprecated
routers to it such as .bind(), .delegate() and .live().
All these three are now built-in and fully compatible with .on()
* Add 'XXX:' comments for suspicious code that I don't want to change
as part of a clean up commit.
* Remove unused variables (several var x = this; where x was not
used anywhere, possibly from boilerplate copy/paste)
* Follows-up Trevor's commit that converts test suites to the new
QUnit format. Also removed the globals since we no longer use those
any more.
Change-Id: I7e37c9bff812e371c7f65a6fd85d9e2af3e0a22f
2012-07-27 08:43:33 +00:00
|
|
|
ve.ce.Surface.prototype.documentOnBlur = function () {
|
2013-09-07 00:59:42 +00:00
|
|
|
this.eventSequencer.detach();
|
2013-09-07 01:03:10 +00:00
|
|
|
this.surfaceObserver.stopTimerLoop();
|
|
|
|
this.surfaceObserver.pollOnce();
|
2013-03-26 20:46:15 +00:00
|
|
|
this.dragging = false;
|
2013-11-27 21:30:25 +00:00
|
|
|
this.emit( 'blur' );
|
2012-04-06 15:10:30 +00:00
|
|
|
};
|
|
|
|
|
Make use of new jshint options
* Restricting "camelcase":
No changes, we were passing all of these already
* Explicitly unrestricting "forin" and "plusplus"
These are off by default in node-jshint, but some distro of jshint
and editors that use their own wrapper around jshint instead of
node-jshint (Eclipse?) may have different defaults. Therefor
setting them to false explicitly. This also serves as a reminder
for the future so we'll always know we don't pass that, in case
we would want to change that.
* Fix order ("quotemark" before "regexp")
* Restricting "unused"
We're not passing all of this, which is why I've set it to false
for now. But I did put it in .jshintrc as placeholder.
I've fixed most of them, there's some left where there is no clean
solution.
* While at it fix a few issues:
- Unused variables ($target, $window)
- Bad practices (using jQuery context for find instead of creation)
- Redundant /*global */ comments
- Parameters that are not used and don't have documentation either
- Lines longer than 100 chars @ 4 spaces/tab
* Note:
- ve.ce.Surface.prototype.onChange takes two arguments but never
uses the former. And even the second one can be null/undefined.
Aside from that, the .change() function emits
another event for the transaction already. Looks like this
should be refactored a bit, two more separated events probably
or one that is actually used better.
- Also cleaned up a lot of comments, some of which were missing,
others were incorrect
- Reworked the contentChange event so we are no longer using the
word new as an object key; expanded a complex object into multiple
arguments being passed through the event to make it easier to work
with and document
Change-Id: I8490815a508c6c379d5f9a743bb4aefd14576aa6
2012-08-07 06:02:18 +00:00
|
|
|
/**
|
2013-01-15 23:38:49 +00:00
|
|
|
* Handle document mouse down events.
|
Make use of new jshint options
* Restricting "camelcase":
No changes, we were passing all of these already
* Explicitly unrestricting "forin" and "plusplus"
These are off by default in node-jshint, but some distro of jshint
and editors that use their own wrapper around jshint instead of
node-jshint (Eclipse?) may have different defaults. Therefor
setting them to false explicitly. This also serves as a reminder
for the future so we'll always know we don't pass that, in case
we would want to change that.
* Fix order ("quotemark" before "regexp")
* Restricting "unused"
We're not passing all of this, which is why I've set it to false
for now. But I did put it in .jshintrc as placeholder.
I've fixed most of them, there's some left where there is no clean
solution.
* While at it fix a few issues:
- Unused variables ($target, $window)
- Bad practices (using jQuery context for find instead of creation)
- Redundant /*global */ comments
- Parameters that are not used and don't have documentation either
- Lines longer than 100 chars @ 4 spaces/tab
* Note:
- ve.ce.Surface.prototype.onChange takes two arguments but never
uses the former. And even the second one can be null/undefined.
Aside from that, the .change() function emits
another event for the transaction already. Looks like this
should be refactored a bit, two more separated events probably
or one that is actually used better.
- Also cleaned up a lot of comments, some of which were missing,
others were incorrect
- Reworked the contentChange event so we are no longer using the
word new as an object key; expanded a complex object into multiple
arguments being passed through the event to make it easier to work
with and document
Change-Id: I8490815a508c6c379d5f9a743bb4aefd14576aa6
2012-08-07 06:02:18 +00:00
|
|
|
*
|
|
|
|
* @method
|
Major UI refactoring and improvements
Objective:
Refactor UI widgets, improve usability and accessibility of menus, general cleanup and style improvements.
Extras:
Fixed documentation in a few other files to make descriptions of jQuery event arguments more consistent, classes inherit correctly, and made use of the @cfg functionality in jsduck.
Changes:
.docs/config.json
* Added window, HTMLDocument, HTMLElement, DocumentFragment and XMLHttpRequest to externals, so jsduck doesn't throw warnings when they are used
demos/ve/index.php, modules/ve/test/index.php, VisualEditor.php
* Moved widgets above tools (since tools use widgets)
demos/ve/index.php
* Refactored widget initialization to use options
* Renamed variables to match widget names
ve.init.mw.ViewPageTarget.css
* Adjusted text sizes to make widgets work normally
* Added margins for buttons in toolbar (since button widgets
don't have any)
* Removed styles for init buttons (button widgets now)
ve.init.mw.ViewPageTarget.js
* Switched to using button widgets (involved moving things around
a bit)
ve.ui.LinkInspector.js, ve.ui.MWLinkInspector.js
* Renamed static property "inputWidget" to
"linkTargetInputWidget" to better reflect the required base class
for the properties value
icons.ai, check.png, check.svg
* Added "check" icon, used in menu right now to show which item
is selected
ve.ui.Icons-raster.css, ve.ui.Icons-vector.css
* Added check icon
* Removed :before pseudo selectors from most of the icon classes (not need by button tool anymore, makes them more reusable now)
ve.ui.Tool.css
* Adjusted drop down tool styles so menu appears below, instead
of on top, of the label
* Adjusted paragraph font size to better match actual content
* Updated class names to still work with menu widget changes
(items are their own widgets now)
* Updated selectors as per changes in the structure of button tools
ve.ui.Widget.css
* Added styles for buttons and menu items
* Adjusted menu styles
ve.ui.*ButtonTool.js
* Added config options argument passthrough
ve.ui.ButtonTool.js
* Moved var statement to the top inside constructor
* Switched to using "a" tag to get cross-browser :active support
* Added icon to inside of button to make icon styles more reusable
* Removed disabled support (now provided by widget parent class)
ve.ui.FormatDropDownTool.js
* Updated options initialization to construct menu item objects
* Modified handling of items to account for changes in menu and
item classes
* Optimized onUpdateState method a bit, adding early exit to
inner loop
ve.ui.ButtonTool.js, ve.ui.DropdownTool.js, ve.ui.Context.js,
ve.ui.Frame, ve.ui.Tool.js, ve.ui.Widget.js
* Added chain ability to non-getter methods
ve.ui.DropdownTool.js
* Removed items argument to constructor
* Updated code as per changes in menu class
* Fixed inconsistent naming of event handler methods
* Removed item event handling (now handled by items directly)
* Made use of this.$$ to ensure tool works in other frames
ve.ui.Tool.js
* Made tools inherit from widget
* Moved trigger registry event handler to a method
ve.ui.Context.js
* Switched from using menu to contain toolbar to a simple wrapper
ve.ui.js
* Added get$$ method, a convenience function for binding jQuery
to a specific document context
ve.ui.*Widget.js
* Switched to using a config options object instead of individual arguments
* Added options
* Factored out flags and labels into their own classes
* Refactored value setting methods for inputs
ve.ui.MenuWidget.js, ve.ui.MenuItemWidget.js
* Broke items out into their own classes
* Redesigned API
* Updated code that uses these classes
* Added support for keyboard interaction
* Made items flash when selected (delaying the hiding of the menu for 200ms)
ve.ui.LinkTargetInputWidget.js, ve.ui.MWLinkTargetInputWidget
* Refactored annotation setting methods
Change-Id: I7769bd5a5b79f1ab36f258ef9f2be583ca503ce6
2013-02-20 23:25:12 +00:00
|
|
|
* @param {jQuery.Event} e Mouse down event
|
Make use of new jshint options
* Restricting "camelcase":
No changes, we were passing all of these already
* Explicitly unrestricting "forin" and "plusplus"
These are off by default in node-jshint, but some distro of jshint
and editors that use their own wrapper around jshint instead of
node-jshint (Eclipse?) may have different defaults. Therefor
setting them to false explicitly. This also serves as a reminder
for the future so we'll always know we don't pass that, in case
we would want to change that.
* Fix order ("quotemark" before "regexp")
* Restricting "unused"
We're not passing all of this, which is why I've set it to false
for now. But I did put it in .jshintrc as placeholder.
I've fixed most of them, there's some left where there is no clean
solution.
* While at it fix a few issues:
- Unused variables ($target, $window)
- Bad practices (using jQuery context for find instead of creation)
- Redundant /*global */ comments
- Parameters that are not used and don't have documentation either
- Lines longer than 100 chars @ 4 spaces/tab
* Note:
- ve.ce.Surface.prototype.onChange takes two arguments but never
uses the former. And even the second one can be null/undefined.
Aside from that, the .change() function emits
another event for the transaction already. Looks like this
should be refactored a bit, two more separated events probably
or one that is actually used better.
- Also cleaned up a lot of comments, some of which were missing,
others were incorrect
- Reworked the contentChange event so we are no longer using the
word new as an object key; expanded a complex object into multiple
arguments being passed through the event to make it easier to work
with and document
Change-Id: I8490815a508c6c379d5f9a743bb4aefd14576aa6
2012-08-07 06:02:18 +00:00
|
|
|
*/
|
2013-01-15 23:38:49 +00:00
|
|
|
ve.ce.Surface.prototype.onDocumentMouseDown = function ( e ) {
|
2013-06-23 21:49:44 +00:00
|
|
|
var selection, node;
|
|
|
|
|
2012-11-02 22:45:26 +00:00
|
|
|
// Remember the mouse is down
|
|
|
|
this.dragging = true;
|
|
|
|
|
2012-10-04 20:59:29 +00:00
|
|
|
// Old code to figure out if user clicked inside the document or not - leave it here for now
|
2013-11-01 19:45:59 +00:00
|
|
|
// this.$( e.target ).closest( '.ve-ce-documentNode' ).length === 0
|
2012-04-27 22:26:38 +00:00
|
|
|
|
2012-10-04 20:59:29 +00:00
|
|
|
if ( e.which === 1 ) {
|
2013-09-07 01:03:10 +00:00
|
|
|
this.surfaceObserver.stopTimerLoop();
|
|
|
|
// TODO: guard with incRenderLock?
|
|
|
|
this.surfaceObserver.pollOnce();
|
2012-04-27 22:26:38 +00:00
|
|
|
}
|
2012-06-20 01:20:28 +00:00
|
|
|
|
2013-06-23 21:49:44 +00:00
|
|
|
// Handle triple click
|
|
|
|
if ( this.getClickCount( e.originalEvent ) >= 3 ) {
|
|
|
|
// Browser default behaviour for triple click won't behave as we want
|
2012-06-20 01:20:28 +00:00
|
|
|
e.preventDefault();
|
2013-06-23 21:49:44 +00:00
|
|
|
|
|
|
|
selection = this.model.getSelection();
|
|
|
|
node = this.documentView.getDocumentNode().getNodeFromOffset( selection.start );
|
|
|
|
// Find the nearest non-content node
|
|
|
|
while ( node.parent !== null && node.model.isContent() ) {
|
|
|
|
node = node.parent;
|
|
|
|
}
|
2013-10-15 18:36:02 +00:00
|
|
|
this.model.setSelection( node.model.getRange() );
|
2012-06-20 01:20:28 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2012-10-04 20:59:29 +00:00
|
|
|
/**
|
2013-01-15 23:38:49 +00:00
|
|
|
* Handle document mouse up events.
|
2012-10-04 20:59:29 +00:00
|
|
|
*
|
|
|
|
* @method
|
Major UI refactoring and improvements
Objective:
Refactor UI widgets, improve usability and accessibility of menus, general cleanup and style improvements.
Extras:
Fixed documentation in a few other files to make descriptions of jQuery event arguments more consistent, classes inherit correctly, and made use of the @cfg functionality in jsduck.
Changes:
.docs/config.json
* Added window, HTMLDocument, HTMLElement, DocumentFragment and XMLHttpRequest to externals, so jsduck doesn't throw warnings when they are used
demos/ve/index.php, modules/ve/test/index.php, VisualEditor.php
* Moved widgets above tools (since tools use widgets)
demos/ve/index.php
* Refactored widget initialization to use options
* Renamed variables to match widget names
ve.init.mw.ViewPageTarget.css
* Adjusted text sizes to make widgets work normally
* Added margins for buttons in toolbar (since button widgets
don't have any)
* Removed styles for init buttons (button widgets now)
ve.init.mw.ViewPageTarget.js
* Switched to using button widgets (involved moving things around
a bit)
ve.ui.LinkInspector.js, ve.ui.MWLinkInspector.js
* Renamed static property "inputWidget" to
"linkTargetInputWidget" to better reflect the required base class
for the properties value
icons.ai, check.png, check.svg
* Added "check" icon, used in menu right now to show which item
is selected
ve.ui.Icons-raster.css, ve.ui.Icons-vector.css
* Added check icon
* Removed :before pseudo selectors from most of the icon classes (not need by button tool anymore, makes them more reusable now)
ve.ui.Tool.css
* Adjusted drop down tool styles so menu appears below, instead
of on top, of the label
* Adjusted paragraph font size to better match actual content
* Updated class names to still work with menu widget changes
(items are their own widgets now)
* Updated selectors as per changes in the structure of button tools
ve.ui.Widget.css
* Added styles for buttons and menu items
* Adjusted menu styles
ve.ui.*ButtonTool.js
* Added config options argument passthrough
ve.ui.ButtonTool.js
* Moved var statement to the top inside constructor
* Switched to using "a" tag to get cross-browser :active support
* Added icon to inside of button to make icon styles more reusable
* Removed disabled support (now provided by widget parent class)
ve.ui.FormatDropDownTool.js
* Updated options initialization to construct menu item objects
* Modified handling of items to account for changes in menu and
item classes
* Optimized onUpdateState method a bit, adding early exit to
inner loop
ve.ui.ButtonTool.js, ve.ui.DropdownTool.js, ve.ui.Context.js,
ve.ui.Frame, ve.ui.Tool.js, ve.ui.Widget.js
* Added chain ability to non-getter methods
ve.ui.DropdownTool.js
* Removed items argument to constructor
* Updated code as per changes in menu class
* Fixed inconsistent naming of event handler methods
* Removed item event handling (now handled by items directly)
* Made use of this.$$ to ensure tool works in other frames
ve.ui.Tool.js
* Made tools inherit from widget
* Moved trigger registry event handler to a method
ve.ui.Context.js
* Switched from using menu to contain toolbar to a simple wrapper
ve.ui.js
* Added get$$ method, a convenience function for binding jQuery
to a specific document context
ve.ui.*Widget.js
* Switched to using a config options object instead of individual arguments
* Added options
* Factored out flags and labels into their own classes
* Refactored value setting methods for inputs
ve.ui.MenuWidget.js, ve.ui.MenuItemWidget.js
* Broke items out into their own classes
* Redesigned API
* Updated code that uses these classes
* Added support for keyboard interaction
* Made items flash when selected (delaying the hiding of the menu for 200ms)
ve.ui.LinkTargetInputWidget.js, ve.ui.MWLinkTargetInputWidget
* Refactored annotation setting methods
Change-Id: I7769bd5a5b79f1ab36f258ef9f2be583ca503ce6
2013-02-20 23:25:12 +00:00
|
|
|
* @param {jQuery.Event} e Mouse up event
|
2013-10-22 17:54:59 +00:00
|
|
|
* @fires selectionEnd
|
2012-10-04 20:59:29 +00:00
|
|
|
*/
|
2013-01-15 23:38:49 +00:00
|
|
|
ve.ce.Surface.prototype.onDocumentMouseUp = function ( e ) {
|
2013-09-07 01:03:10 +00:00
|
|
|
this.surfaceObserver.startTimerLoop();
|
|
|
|
// TODO: guard with incRenderLock?
|
|
|
|
this.surfaceObserver.pollOnce();
|
2012-11-02 22:45:26 +00:00
|
|
|
if ( !e.shiftKey && this.selecting ) {
|
|
|
|
this.emit( 'selectionEnd' );
|
|
|
|
this.selecting = false;
|
|
|
|
}
|
|
|
|
this.dragging = false;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
2013-01-15 23:38:49 +00:00
|
|
|
* Handle document mouse move events.
|
2012-11-02 22:45:26 +00:00
|
|
|
*
|
|
|
|
* @method
|
Major UI refactoring and improvements
Objective:
Refactor UI widgets, improve usability and accessibility of menus, general cleanup and style improvements.
Extras:
Fixed documentation in a few other files to make descriptions of jQuery event arguments more consistent, classes inherit correctly, and made use of the @cfg functionality in jsduck.
Changes:
.docs/config.json
* Added window, HTMLDocument, HTMLElement, DocumentFragment and XMLHttpRequest to externals, so jsduck doesn't throw warnings when they are used
demos/ve/index.php, modules/ve/test/index.php, VisualEditor.php
* Moved widgets above tools (since tools use widgets)
demos/ve/index.php
* Refactored widget initialization to use options
* Renamed variables to match widget names
ve.init.mw.ViewPageTarget.css
* Adjusted text sizes to make widgets work normally
* Added margins for buttons in toolbar (since button widgets
don't have any)
* Removed styles for init buttons (button widgets now)
ve.init.mw.ViewPageTarget.js
* Switched to using button widgets (involved moving things around
a bit)
ve.ui.LinkInspector.js, ve.ui.MWLinkInspector.js
* Renamed static property "inputWidget" to
"linkTargetInputWidget" to better reflect the required base class
for the properties value
icons.ai, check.png, check.svg
* Added "check" icon, used in menu right now to show which item
is selected
ve.ui.Icons-raster.css, ve.ui.Icons-vector.css
* Added check icon
* Removed :before pseudo selectors from most of the icon classes (not need by button tool anymore, makes them more reusable now)
ve.ui.Tool.css
* Adjusted drop down tool styles so menu appears below, instead
of on top, of the label
* Adjusted paragraph font size to better match actual content
* Updated class names to still work with menu widget changes
(items are their own widgets now)
* Updated selectors as per changes in the structure of button tools
ve.ui.Widget.css
* Added styles for buttons and menu items
* Adjusted menu styles
ve.ui.*ButtonTool.js
* Added config options argument passthrough
ve.ui.ButtonTool.js
* Moved var statement to the top inside constructor
* Switched to using "a" tag to get cross-browser :active support
* Added icon to inside of button to make icon styles more reusable
* Removed disabled support (now provided by widget parent class)
ve.ui.FormatDropDownTool.js
* Updated options initialization to construct menu item objects
* Modified handling of items to account for changes in menu and
item classes
* Optimized onUpdateState method a bit, adding early exit to
inner loop
ve.ui.ButtonTool.js, ve.ui.DropdownTool.js, ve.ui.Context.js,
ve.ui.Frame, ve.ui.Tool.js, ve.ui.Widget.js
* Added chain ability to non-getter methods
ve.ui.DropdownTool.js
* Removed items argument to constructor
* Updated code as per changes in menu class
* Fixed inconsistent naming of event handler methods
* Removed item event handling (now handled by items directly)
* Made use of this.$$ to ensure tool works in other frames
ve.ui.Tool.js
* Made tools inherit from widget
* Moved trigger registry event handler to a method
ve.ui.Context.js
* Switched from using menu to contain toolbar to a simple wrapper
ve.ui.js
* Added get$$ method, a convenience function for binding jQuery
to a specific document context
ve.ui.*Widget.js
* Switched to using a config options object instead of individual arguments
* Added options
* Factored out flags and labels into their own classes
* Refactored value setting methods for inputs
ve.ui.MenuWidget.js, ve.ui.MenuItemWidget.js
* Broke items out into their own classes
* Redesigned API
* Updated code that uses these classes
* Added support for keyboard interaction
* Made items flash when selected (delaying the hiding of the menu for 200ms)
ve.ui.LinkTargetInputWidget.js, ve.ui.MWLinkTargetInputWidget
* Refactored annotation setting methods
Change-Id: I7769bd5a5b79f1ab36f258ef9f2be583ca503ce6
2013-02-20 23:25:12 +00:00
|
|
|
* @param {jQuery.Event} e Mouse move event
|
2013-10-22 17:54:59 +00:00
|
|
|
* @fires selectionStart
|
2012-11-02 22:45:26 +00:00
|
|
|
*/
|
2013-01-15 23:38:49 +00:00
|
|
|
ve.ce.Surface.prototype.onDocumentMouseMove = function () {
|
2012-11-02 22:45:26 +00:00
|
|
|
// Detect beginning of selection by moving mouse while dragging
|
|
|
|
if ( this.dragging && !this.selecting ) {
|
|
|
|
this.selecting = true;
|
|
|
|
this.emit( 'selectionStart' );
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
2013-04-15 17:54:49 +00:00
|
|
|
* Handle document dragover events.
|
|
|
|
*
|
|
|
|
* Limits native drag and drop behavior.
|
|
|
|
*
|
|
|
|
* @method
|
|
|
|
* @param {jQuery.Event} e Drag over event
|
|
|
|
*/
|
|
|
|
ve.ce.Surface.prototype.onDocumentDragOver = function () {
|
|
|
|
if ( !this.relocating ) {
|
|
|
|
return false;
|
|
|
|
} else if ( this.selecting ) {
|
|
|
|
this.emit( 'selectionEnd' );
|
|
|
|
this.selecting = false;
|
|
|
|
this.dragging = false;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Handle document drop events.
|
|
|
|
*
|
|
|
|
* Limits native drag and drop behavior.
|
2013-01-16 21:51:05 +00:00
|
|
|
*
|
2013-04-15 17:54:49 +00:00
|
|
|
* TODO: Look into using drag and drop data transfer to embed the dragged element's original range
|
|
|
|
* (for dragging within one document) and serialized linear model data (for dragging between
|
|
|
|
* multiple documents) and use a special mimetype, like application-x/VisualEditor, to allow
|
|
|
|
* dragover and drop events on the surface, removing the need to give the surface explicit
|
|
|
|
* instructions to allow and prevent dragging and dropping a certain node.
|
2012-11-02 22:45:26 +00:00
|
|
|
*
|
|
|
|
* @method
|
2013-04-15 17:54:49 +00:00
|
|
|
* @param {jQuery.Event} e Drag drop event
|
2012-11-02 22:45:26 +00:00
|
|
|
*/
|
2013-04-15 17:54:49 +00:00
|
|
|
ve.ce.Surface.prototype.onDocumentDrop = function ( e ) {
|
|
|
|
var node = this.relocating;
|
|
|
|
|
|
|
|
if ( node ) {
|
|
|
|
// Process drop operation after native drop has been prevented below
|
|
|
|
setTimeout( ve.bind( function () {
|
|
|
|
var dropPoint, nodeData, originFragment, targetFragment,
|
|
|
|
nodeRange = node.getModel().getOuterRange();
|
|
|
|
|
|
|
|
// Get a fragment from the drop point
|
2013-06-18 05:04:56 +00:00
|
|
|
dropPoint = rangy.positionFromPoint(
|
|
|
|
e.originalEvent.pageX - this.$document.scrollLeft(),
|
|
|
|
e.originalEvent.pageY - this.$document.scrollTop()
|
|
|
|
);
|
2013-04-15 17:54:49 +00:00
|
|
|
if ( !dropPoint ) {
|
|
|
|
// Getting position from point supported
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
targetFragment = this.model.getFragment(
|
|
|
|
new ve.Range( ve.ce.getOffset( dropPoint.node, dropPoint.offset ) ), false
|
|
|
|
);
|
|
|
|
|
|
|
|
// Get a fragment and data of the node being dragged
|
|
|
|
originFragment = this.model.getFragment( nodeRange, false );
|
|
|
|
nodeData = originFragment.getData();
|
|
|
|
|
|
|
|
// Remove node from old location (auto-updates targetFragment's range)
|
2013-04-22 11:20:26 +00:00
|
|
|
originFragment.removeContent();
|
2013-04-15 17:54:49 +00:00
|
|
|
|
|
|
|
// Re-insert node at new location and re-select it
|
2013-04-23 16:05:48 +00:00
|
|
|
targetFragment.insertContent( nodeData ).select();
|
2013-04-15 17:54:49 +00:00
|
|
|
}, this ) );
|
|
|
|
}
|
|
|
|
|
2013-01-16 21:51:05 +00:00
|
|
|
return false;
|
2012-10-04 20:59:29 +00:00
|
|
|
};
|
|
|
|
|
Make use of new jshint options
* Restricting "camelcase":
No changes, we were passing all of these already
* Explicitly unrestricting "forin" and "plusplus"
These are off by default in node-jshint, but some distro of jshint
and editors that use their own wrapper around jshint instead of
node-jshint (Eclipse?) may have different defaults. Therefor
setting them to false explicitly. This also serves as a reminder
for the future so we'll always know we don't pass that, in case
we would want to change that.
* Fix order ("quotemark" before "regexp")
* Restricting "unused"
We're not passing all of this, which is why I've set it to false
for now. But I did put it in .jshintrc as placeholder.
I've fixed most of them, there's some left where there is no clean
solution.
* While at it fix a few issues:
- Unused variables ($target, $window)
- Bad practices (using jQuery context for find instead of creation)
- Redundant /*global */ comments
- Parameters that are not used and don't have documentation either
- Lines longer than 100 chars @ 4 spaces/tab
* Note:
- ve.ce.Surface.prototype.onChange takes two arguments but never
uses the former. And even the second one can be null/undefined.
Aside from that, the .change() function emits
another event for the transaction already. Looks like this
should be refactored a bit, two more separated events probably
or one that is actually used better.
- Also cleaned up a lot of comments, some of which were missing,
others were incorrect
- Reworked the contentChange event so we are no longer using the
word new as an object key; expanded a complex object into multiple
arguments being passed through the event to make it easier to work
with and document
Change-Id: I8490815a508c6c379d5f9a743bb4aefd14576aa6
2012-08-07 06:02:18 +00:00
|
|
|
/**
|
2013-01-15 23:38:49 +00:00
|
|
|
* Handle document key down events.
|
Make use of new jshint options
* Restricting "camelcase":
No changes, we were passing all of these already
* Explicitly unrestricting "forin" and "plusplus"
These are off by default in node-jshint, but some distro of jshint
and editors that use their own wrapper around jshint instead of
node-jshint (Eclipse?) may have different defaults. Therefor
setting them to false explicitly. This also serves as a reminder
for the future so we'll always know we don't pass that, in case
we would want to change that.
* Fix order ("quotemark" before "regexp")
* Restricting "unused"
We're not passing all of this, which is why I've set it to false
for now. But I did put it in .jshintrc as placeholder.
I've fixed most of them, there's some left where there is no clean
solution.
* While at it fix a few issues:
- Unused variables ($target, $window)
- Bad practices (using jQuery context for find instead of creation)
- Redundant /*global */ comments
- Parameters that are not used and don't have documentation either
- Lines longer than 100 chars @ 4 spaces/tab
* Note:
- ve.ce.Surface.prototype.onChange takes two arguments but never
uses the former. And even the second one can be null/undefined.
Aside from that, the .change() function emits
another event for the transaction already. Looks like this
should be refactored a bit, two more separated events probably
or one that is actually used better.
- Also cleaned up a lot of comments, some of which were missing,
others were incorrect
- Reworked the contentChange event so we are no longer using the
word new as an object key; expanded a complex object into multiple
arguments being passed through the event to make it easier to work
with and document
Change-Id: I8490815a508c6c379d5f9a743bb4aefd14576aa6
2012-08-07 06:02:18 +00:00
|
|
|
*
|
|
|
|
* @method
|
Major UI refactoring and improvements
Objective:
Refactor UI widgets, improve usability and accessibility of menus, general cleanup and style improvements.
Extras:
Fixed documentation in a few other files to make descriptions of jQuery event arguments more consistent, classes inherit correctly, and made use of the @cfg functionality in jsduck.
Changes:
.docs/config.json
* Added window, HTMLDocument, HTMLElement, DocumentFragment and XMLHttpRequest to externals, so jsduck doesn't throw warnings when they are used
demos/ve/index.php, modules/ve/test/index.php, VisualEditor.php
* Moved widgets above tools (since tools use widgets)
demos/ve/index.php
* Refactored widget initialization to use options
* Renamed variables to match widget names
ve.init.mw.ViewPageTarget.css
* Adjusted text sizes to make widgets work normally
* Added margins for buttons in toolbar (since button widgets
don't have any)
* Removed styles for init buttons (button widgets now)
ve.init.mw.ViewPageTarget.js
* Switched to using button widgets (involved moving things around
a bit)
ve.ui.LinkInspector.js, ve.ui.MWLinkInspector.js
* Renamed static property "inputWidget" to
"linkTargetInputWidget" to better reflect the required base class
for the properties value
icons.ai, check.png, check.svg
* Added "check" icon, used in menu right now to show which item
is selected
ve.ui.Icons-raster.css, ve.ui.Icons-vector.css
* Added check icon
* Removed :before pseudo selectors from most of the icon classes (not need by button tool anymore, makes them more reusable now)
ve.ui.Tool.css
* Adjusted drop down tool styles so menu appears below, instead
of on top, of the label
* Adjusted paragraph font size to better match actual content
* Updated class names to still work with menu widget changes
(items are their own widgets now)
* Updated selectors as per changes in the structure of button tools
ve.ui.Widget.css
* Added styles for buttons and menu items
* Adjusted menu styles
ve.ui.*ButtonTool.js
* Added config options argument passthrough
ve.ui.ButtonTool.js
* Moved var statement to the top inside constructor
* Switched to using "a" tag to get cross-browser :active support
* Added icon to inside of button to make icon styles more reusable
* Removed disabled support (now provided by widget parent class)
ve.ui.FormatDropDownTool.js
* Updated options initialization to construct menu item objects
* Modified handling of items to account for changes in menu and
item classes
* Optimized onUpdateState method a bit, adding early exit to
inner loop
ve.ui.ButtonTool.js, ve.ui.DropdownTool.js, ve.ui.Context.js,
ve.ui.Frame, ve.ui.Tool.js, ve.ui.Widget.js
* Added chain ability to non-getter methods
ve.ui.DropdownTool.js
* Removed items argument to constructor
* Updated code as per changes in menu class
* Fixed inconsistent naming of event handler methods
* Removed item event handling (now handled by items directly)
* Made use of this.$$ to ensure tool works in other frames
ve.ui.Tool.js
* Made tools inherit from widget
* Moved trigger registry event handler to a method
ve.ui.Context.js
* Switched from using menu to contain toolbar to a simple wrapper
ve.ui.js
* Added get$$ method, a convenience function for binding jQuery
to a specific document context
ve.ui.*Widget.js
* Switched to using a config options object instead of individual arguments
* Added options
* Factored out flags and labels into their own classes
* Refactored value setting methods for inputs
ve.ui.MenuWidget.js, ve.ui.MenuItemWidget.js
* Broke items out into their own classes
* Redesigned API
* Updated code that uses these classes
* Added support for keyboard interaction
* Made items flash when selected (delaying the hiding of the menu for 200ms)
ve.ui.LinkTargetInputWidget.js, ve.ui.MWLinkTargetInputWidget
* Refactored annotation setting methods
Change-Id: I7769bd5a5b79f1ab36f258ef9f2be583ca503ce6
2013-02-20 23:25:12 +00:00
|
|
|
* @param {jQuery.Event} e Key down event
|
2013-10-22 17:54:59 +00:00
|
|
|
* @fires selectionStart
|
Make use of new jshint options
* Restricting "camelcase":
No changes, we were passing all of these already
* Explicitly unrestricting "forin" and "plusplus"
These are off by default in node-jshint, but some distro of jshint
and editors that use their own wrapper around jshint instead of
node-jshint (Eclipse?) may have different defaults. Therefor
setting them to false explicitly. This also serves as a reminder
for the future so we'll always know we don't pass that, in case
we would want to change that.
* Fix order ("quotemark" before "regexp")
* Restricting "unused"
We're not passing all of this, which is why I've set it to false
for now. But I did put it in .jshintrc as placeholder.
I've fixed most of them, there's some left where there is no clean
solution.
* While at it fix a few issues:
- Unused variables ($target, $window)
- Bad practices (using jQuery context for find instead of creation)
- Redundant /*global */ comments
- Parameters that are not used and don't have documentation either
- Lines longer than 100 chars @ 4 spaces/tab
* Note:
- ve.ce.Surface.prototype.onChange takes two arguments but never
uses the former. And even the second one can be null/undefined.
Aside from that, the .change() function emits
another event for the transaction already. Looks like this
should be refactored a bit, two more separated events probably
or one that is actually used better.
- Also cleaned up a lot of comments, some of which were missing,
others were incorrect
- Reworked the contentChange event so we are no longer using the
word new as an object key; expanded a complex object into multiple
arguments being passed through the event to make it easier to work
with and document
Change-Id: I8490815a508c6c379d5f9a743bb4aefd14576aa6
2012-08-07 06:02:18 +00:00
|
|
|
*/
|
2013-01-15 23:38:49 +00:00
|
|
|
ve.ce.Surface.prototype.onDocumentKeyDown = function ( e ) {
|
2013-10-01 02:57:18 +00:00
|
|
|
var trigger,
|
|
|
|
updateFromModel = false;
|
The Great ve.ui.Surface refactor of 2013
Prologue:
Farewell ve.Editor my good chap… Oh, hey there HTML frames - I didn't
see you there! In a world where iframes are outlaws, and symbols like
document and window are global, there were more than a few assumptions
about which document or window was being used. But fear not - for this
commit (probably) tracks them all down, leaving a trail of
iframe-compatible awesomeness in its wake. With the great ve.ui.Surface
now able to be used inside of iframes, let the reference editing
commence. But there, lurking in the darkness is a DM issue so fierce it
may take Roan and/or Ed up to 3 whole hours to sort it out.
Note to Roan and/or Ed:
Editing references seems to work fine, but when saving the page there
are "no changes" which is a reasonable indication to the contrary.
Objectives:
* Make it possible to have multiple surfaces be instantiated, get along
nicely, and be embedded inside of iframes if needed.
* Make reference content editable within a dialog
Approach:
* Move what's left of ve.Editor to ve.ui.Surface and essentially
obliterate all use of it
* Make even more stuff inherit from ve.Element (long live this.$$)
* Use the correct document or window anywhere it was being assumed to be
the top level one
* Resolve stacking order issues by removing the excessive use of z-index
and introducing global and local overlay elements for each editor
* Add a surface to the reference dialog, load up the reference contents
and save them back on apply
* Actually destroy what we create in ce and ui surfaces
* Add recursive frame offset calculation method to ve.Element
* Moved ve.ce.Surface's getSelectionRect method to the prototype
Bonus:
* Move ve.ce.DocumentNode.css contents to ve.ce.Node.css (not sure why it
was separate in the first place, but I'm likely the one to blame)
* Fix blatant lies in documentation
* Whitespace cleanup here and there
* Get rid of ve.ui.Window overlays - not used or needed
Change-Id: Iede83e7d24f7cb249b6ba3dc45d770445b862e08
2013-05-20 22:45:50 +00:00
|
|
|
|
2013-06-12 22:34:15 +00:00
|
|
|
// Ignore keydowns while in IME mode but do not preventDefault them (so text actually appear on
|
|
|
|
// the screen).
|
2012-10-11 18:31:28 +00:00
|
|
|
if ( this.inIme === true ) {
|
|
|
|
return;
|
|
|
|
}
|
2013-03-28 20:15:14 +00:00
|
|
|
|
2013-06-12 22:34:15 +00:00
|
|
|
// When entering IME mode IE first keydown (e.which = 229) before it fires compositionstart, so
|
|
|
|
// IME detection have to happen here instead of onDocumentCompositionStart.
|
|
|
|
// TODO: This code and code in onDocumentCompositionStart are very similar, consider moving them
|
|
|
|
// to one method.
|
2013-04-09 00:50:34 +00:00
|
|
|
if ( $.browser.msie === true && e.which === 229 ) {
|
|
|
|
this.inIme = true;
|
|
|
|
this.handleInsertion();
|
|
|
|
return;
|
2012-10-14 19:28:06 +00:00
|
|
|
}
|
2013-04-09 00:50:34 +00:00
|
|
|
|
2013-09-07 01:03:10 +00:00
|
|
|
this.surfaceObserver.stopTimerLoop();
|
|
|
|
this.incRenderLock();
|
|
|
|
try {
|
|
|
|
// TODO: is this correct?
|
|
|
|
this.surfaceObserver.pollOnce();
|
|
|
|
} finally {
|
|
|
|
this.decRenderLock();
|
|
|
|
}
|
2013-06-12 22:34:15 +00:00
|
|
|
switch ( e.keyCode ) {
|
2013-10-09 20:09:59 +00:00
|
|
|
case OO.ui.Keys.LEFT:
|
|
|
|
case OO.ui.Keys.RIGHT:
|
|
|
|
case OO.ui.Keys.UP:
|
|
|
|
case OO.ui.Keys.DOWN:
|
2013-06-12 22:34:15 +00:00
|
|
|
if ( !this.dragging && !this.selecting && e.shiftKey ) {
|
|
|
|
this.selecting = true;
|
|
|
|
this.emit( 'selectionStart' );
|
|
|
|
}
|
|
|
|
if ( ve.ce.isLeftOrRightArrowKey( e.keyCode ) ) {
|
|
|
|
this.handleLeftOrRightArrowKey( e );
|
|
|
|
} else {
|
|
|
|
this.handleUpOrDownArrowKey( e );
|
2013-10-01 02:57:18 +00:00
|
|
|
updateFromModel = true;
|
2013-06-12 22:34:15 +00:00
|
|
|
}
|
|
|
|
break;
|
2013-10-09 20:09:59 +00:00
|
|
|
case OO.ui.Keys.ENTER:
|
2012-06-20 01:20:28 +00:00
|
|
|
e.preventDefault();
|
2013-06-12 22:34:15 +00:00
|
|
|
this.handleEnter( e );
|
2013-10-01 02:57:18 +00:00
|
|
|
updateFromModel = true;
|
2013-06-12 22:34:15 +00:00
|
|
|
break;
|
2013-10-09 20:09:59 +00:00
|
|
|
case OO.ui.Keys.BACKSPACE:
|
2013-06-13 04:07:20 +00:00
|
|
|
e.preventDefault();
|
2013-06-12 22:34:15 +00:00
|
|
|
this.handleDelete( e, true );
|
2013-10-01 02:57:18 +00:00
|
|
|
updateFromModel = true;
|
2013-06-12 22:34:15 +00:00
|
|
|
break;
|
2013-10-09 20:09:59 +00:00
|
|
|
case OO.ui.Keys.DELETE:
|
2013-06-13 04:07:20 +00:00
|
|
|
e.preventDefault();
|
2013-06-12 22:34:15 +00:00
|
|
|
this.handleDelete( e, false );
|
2013-10-01 02:57:18 +00:00
|
|
|
updateFromModel = true;
|
2013-06-12 22:34:15 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
trigger = new ve.ui.Trigger( e );
|
|
|
|
if ( trigger.isComplete() && this.surface.execute( trigger ) ) {
|
|
|
|
e.preventDefault();
|
2013-10-01 02:57:18 +00:00
|
|
|
updateFromModel = true;
|
2013-06-12 22:34:15 +00:00
|
|
|
}
|
|
|
|
break;
|
2012-06-20 01:20:28 +00:00
|
|
|
}
|
2013-10-01 02:57:18 +00:00
|
|
|
if ( !updateFromModel ) {
|
|
|
|
this.incRenderLock();
|
|
|
|
}
|
2013-09-07 01:03:10 +00:00
|
|
|
try {
|
|
|
|
this.surfaceObserver.pollOnce();
|
|
|
|
} finally {
|
2013-10-01 02:57:18 +00:00
|
|
|
if ( !updateFromModel ) {
|
|
|
|
this.decRenderLock();
|
|
|
|
}
|
2013-09-07 01:03:10 +00:00
|
|
|
}
|
|
|
|
this.surfaceObserver.startTimerLoop();
|
2012-04-27 22:26:38 +00:00
|
|
|
};
|
|
|
|
|
Make use of new jshint options
* Restricting "camelcase":
No changes, we were passing all of these already
* Explicitly unrestricting "forin" and "plusplus"
These are off by default in node-jshint, but some distro of jshint
and editors that use their own wrapper around jshint instead of
node-jshint (Eclipse?) may have different defaults. Therefor
setting them to false explicitly. This also serves as a reminder
for the future so we'll always know we don't pass that, in case
we would want to change that.
* Fix order ("quotemark" before "regexp")
* Restricting "unused"
We're not passing all of this, which is why I've set it to false
for now. But I did put it in .jshintrc as placeholder.
I've fixed most of them, there's some left where there is no clean
solution.
* While at it fix a few issues:
- Unused variables ($target, $window)
- Bad practices (using jQuery context for find instead of creation)
- Redundant /*global */ comments
- Parameters that are not used and don't have documentation either
- Lines longer than 100 chars @ 4 spaces/tab
* Note:
- ve.ce.Surface.prototype.onChange takes two arguments but never
uses the former. And even the second one can be null/undefined.
Aside from that, the .change() function emits
another event for the transaction already. Looks like this
should be refactored a bit, two more separated events probably
or one that is actually used better.
- Also cleaned up a lot of comments, some of which were missing,
others were incorrect
- Reworked the contentChange event so we are no longer using the
word new as an object key; expanded a complex object into multiple
arguments being passed through the event to make it easier to work
with and document
Change-Id: I8490815a508c6c379d5f9a743bb4aefd14576aa6
2012-08-07 06:02:18 +00:00
|
|
|
/**
|
2013-01-16 21:51:05 +00:00
|
|
|
* Handle document key press events.
|
Make use of new jshint options
* Restricting "camelcase":
No changes, we were passing all of these already
* Explicitly unrestricting "forin" and "plusplus"
These are off by default in node-jshint, but some distro of jshint
and editors that use their own wrapper around jshint instead of
node-jshint (Eclipse?) may have different defaults. Therefor
setting them to false explicitly. This also serves as a reminder
for the future so we'll always know we don't pass that, in case
we would want to change that.
* Fix order ("quotemark" before "regexp")
* Restricting "unused"
We're not passing all of this, which is why I've set it to false
for now. But I did put it in .jshintrc as placeholder.
I've fixed most of them, there's some left where there is no clean
solution.
* While at it fix a few issues:
- Unused variables ($target, $window)
- Bad practices (using jQuery context for find instead of creation)
- Redundant /*global */ comments
- Parameters that are not used and don't have documentation either
- Lines longer than 100 chars @ 4 spaces/tab
* Note:
- ve.ce.Surface.prototype.onChange takes two arguments but never
uses the former. And even the second one can be null/undefined.
Aside from that, the .change() function emits
another event for the transaction already. Looks like this
should be refactored a bit, two more separated events probably
or one that is actually used better.
- Also cleaned up a lot of comments, some of which were missing,
others were incorrect
- Reworked the contentChange event so we are no longer using the
word new as an object key; expanded a complex object into multiple
arguments being passed through the event to make it easier to work
with and document
Change-Id: I8490815a508c6c379d5f9a743bb4aefd14576aa6
2012-08-07 06:02:18 +00:00
|
|
|
*
|
|
|
|
* @method
|
Major UI refactoring and improvements
Objective:
Refactor UI widgets, improve usability and accessibility of menus, general cleanup and style improvements.
Extras:
Fixed documentation in a few other files to make descriptions of jQuery event arguments more consistent, classes inherit correctly, and made use of the @cfg functionality in jsduck.
Changes:
.docs/config.json
* Added window, HTMLDocument, HTMLElement, DocumentFragment and XMLHttpRequest to externals, so jsduck doesn't throw warnings when they are used
demos/ve/index.php, modules/ve/test/index.php, VisualEditor.php
* Moved widgets above tools (since tools use widgets)
demos/ve/index.php
* Refactored widget initialization to use options
* Renamed variables to match widget names
ve.init.mw.ViewPageTarget.css
* Adjusted text sizes to make widgets work normally
* Added margins for buttons in toolbar (since button widgets
don't have any)
* Removed styles for init buttons (button widgets now)
ve.init.mw.ViewPageTarget.js
* Switched to using button widgets (involved moving things around
a bit)
ve.ui.LinkInspector.js, ve.ui.MWLinkInspector.js
* Renamed static property "inputWidget" to
"linkTargetInputWidget" to better reflect the required base class
for the properties value
icons.ai, check.png, check.svg
* Added "check" icon, used in menu right now to show which item
is selected
ve.ui.Icons-raster.css, ve.ui.Icons-vector.css
* Added check icon
* Removed :before pseudo selectors from most of the icon classes (not need by button tool anymore, makes them more reusable now)
ve.ui.Tool.css
* Adjusted drop down tool styles so menu appears below, instead
of on top, of the label
* Adjusted paragraph font size to better match actual content
* Updated class names to still work with menu widget changes
(items are their own widgets now)
* Updated selectors as per changes in the structure of button tools
ve.ui.Widget.css
* Added styles for buttons and menu items
* Adjusted menu styles
ve.ui.*ButtonTool.js
* Added config options argument passthrough
ve.ui.ButtonTool.js
* Moved var statement to the top inside constructor
* Switched to using "a" tag to get cross-browser :active support
* Added icon to inside of button to make icon styles more reusable
* Removed disabled support (now provided by widget parent class)
ve.ui.FormatDropDownTool.js
* Updated options initialization to construct menu item objects
* Modified handling of items to account for changes in menu and
item classes
* Optimized onUpdateState method a bit, adding early exit to
inner loop
ve.ui.ButtonTool.js, ve.ui.DropdownTool.js, ve.ui.Context.js,
ve.ui.Frame, ve.ui.Tool.js, ve.ui.Widget.js
* Added chain ability to non-getter methods
ve.ui.DropdownTool.js
* Removed items argument to constructor
* Updated code as per changes in menu class
* Fixed inconsistent naming of event handler methods
* Removed item event handling (now handled by items directly)
* Made use of this.$$ to ensure tool works in other frames
ve.ui.Tool.js
* Made tools inherit from widget
* Moved trigger registry event handler to a method
ve.ui.Context.js
* Switched from using menu to contain toolbar to a simple wrapper
ve.ui.js
* Added get$$ method, a convenience function for binding jQuery
to a specific document context
ve.ui.*Widget.js
* Switched to using a config options object instead of individual arguments
* Added options
* Factored out flags and labels into their own classes
* Refactored value setting methods for inputs
ve.ui.MenuWidget.js, ve.ui.MenuItemWidget.js
* Broke items out into their own classes
* Redesigned API
* Updated code that uses these classes
* Added support for keyboard interaction
* Made items flash when selected (delaying the hiding of the menu for 200ms)
ve.ui.LinkTargetInputWidget.js, ve.ui.MWLinkTargetInputWidget
* Refactored annotation setting methods
Change-Id: I7769bd5a5b79f1ab36f258ef9f2be583ca503ce6
2013-02-20 23:25:12 +00:00
|
|
|
* @param {jQuery.Event} e Key press event
|
Make use of new jshint options
* Restricting "camelcase":
No changes, we were passing all of these already
* Explicitly unrestricting "forin" and "plusplus"
These are off by default in node-jshint, but some distro of jshint
and editors that use their own wrapper around jshint instead of
node-jshint (Eclipse?) may have different defaults. Therefor
setting them to false explicitly. This also serves as a reminder
for the future so we'll always know we don't pass that, in case
we would want to change that.
* Fix order ("quotemark" before "regexp")
* Restricting "unused"
We're not passing all of this, which is why I've set it to false
for now. But I did put it in .jshintrc as placeholder.
I've fixed most of them, there's some left where there is no clean
solution.
* While at it fix a few issues:
- Unused variables ($target, $window)
- Bad practices (using jQuery context for find instead of creation)
- Redundant /*global */ comments
- Parameters that are not used and don't have documentation either
- Lines longer than 100 chars @ 4 spaces/tab
* Note:
- ve.ce.Surface.prototype.onChange takes two arguments but never
uses the former. And even the second one can be null/undefined.
Aside from that, the .change() function emits
another event for the transaction already. Looks like this
should be refactored a bit, two more separated events probably
or one that is actually used better.
- Also cleaned up a lot of comments, some of which were missing,
others were incorrect
- Reworked the contentChange event so we are no longer using the
word new as an object key; expanded a complex object into multiple
arguments being passed through the event to make it easier to work
with and document
Change-Id: I8490815a508c6c379d5f9a743bb4aefd14576aa6
2012-08-07 06:02:18 +00:00
|
|
|
*/
|
2013-01-16 21:51:05 +00:00
|
|
|
ve.ce.Surface.prototype.onDocumentKeyPress = function ( e ) {
|
2013-04-09 00:50:34 +00:00
|
|
|
var selection, prevNode, documentModel = this.model.getDocument();
|
|
|
|
|
|
|
|
// Prevent IE from editing Aliens/Entities
|
2013-10-01 02:57:18 +00:00
|
|
|
// This is for cases like <p><div>alien</div></p>, to put the cursor outside
|
|
|
|
// the alien tag.
|
2013-04-09 00:50:34 +00:00
|
|
|
if ( $.browser.msie === true ) {
|
|
|
|
selection = this.model.getSelection();
|
|
|
|
if ( selection.start !== 0 && selection.isCollapsed() ) {
|
|
|
|
prevNode = documentModel.getDocumentNode().getNodeFromOffset( selection.start - 1 );
|
|
|
|
if (
|
|
|
|
!this.documentView.getSlugAtOffset( selection.start ) &&
|
|
|
|
prevNode.isContent() &&
|
|
|
|
documentModel.data.isCloseElementData( selection.start - 1 )
|
|
|
|
) {
|
2013-10-15 18:36:02 +00:00
|
|
|
this.model.setSelection( new ve.Range( selection.start ) );
|
2013-04-09 00:50:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-12 22:03:40 +00:00
|
|
|
// Filter out non-character keys. If those keys wouldn't be filtered out unexpected content
|
|
|
|
// deletion would occur in case when selection is not collapsed and user press home key for
|
|
|
|
// instance (Firefox fires keypress for home key).
|
|
|
|
// TODO: Should be covered with Selenium tests.
|
2013-06-19 17:19:52 +00:00
|
|
|
if ( e.which === 0 || e.charCode === 0 || ve.ce.isShortcutKey( e ) ) {
|
2013-01-16 21:51:05 +00:00
|
|
|
return;
|
|
|
|
}
|
2013-06-12 22:03:40 +00:00
|
|
|
|
2013-01-16 21:51:05 +00:00
|
|
|
this.handleInsertion();
|
2013-08-27 11:26:25 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
2013-09-07 00:59:42 +00:00
|
|
|
* Poll again after the native key press
|
|
|
|
* @param {jQuery.Event} ev
|
2013-08-27 11:26:25 +00:00
|
|
|
*/
|
2013-09-07 00:59:42 +00:00
|
|
|
ve.ce.Surface.prototype.afterDocumentKeyPress = function () {
|
2013-09-07 01:03:10 +00:00
|
|
|
this.surfaceObserver.pollOnce();
|
2013-08-27 11:26:25 +00:00
|
|
|
};
|
|
|
|
|
2013-01-16 21:51:05 +00:00
|
|
|
/**
|
|
|
|
* Handle document key up events.
|
|
|
|
*
|
|
|
|
* @method
|
Major UI refactoring and improvements
Objective:
Refactor UI widgets, improve usability and accessibility of menus, general cleanup and style improvements.
Extras:
Fixed documentation in a few other files to make descriptions of jQuery event arguments more consistent, classes inherit correctly, and made use of the @cfg functionality in jsduck.
Changes:
.docs/config.json
* Added window, HTMLDocument, HTMLElement, DocumentFragment and XMLHttpRequest to externals, so jsduck doesn't throw warnings when they are used
demos/ve/index.php, modules/ve/test/index.php, VisualEditor.php
* Moved widgets above tools (since tools use widgets)
demos/ve/index.php
* Refactored widget initialization to use options
* Renamed variables to match widget names
ve.init.mw.ViewPageTarget.css
* Adjusted text sizes to make widgets work normally
* Added margins for buttons in toolbar (since button widgets
don't have any)
* Removed styles for init buttons (button widgets now)
ve.init.mw.ViewPageTarget.js
* Switched to using button widgets (involved moving things around
a bit)
ve.ui.LinkInspector.js, ve.ui.MWLinkInspector.js
* Renamed static property "inputWidget" to
"linkTargetInputWidget" to better reflect the required base class
for the properties value
icons.ai, check.png, check.svg
* Added "check" icon, used in menu right now to show which item
is selected
ve.ui.Icons-raster.css, ve.ui.Icons-vector.css
* Added check icon
* Removed :before pseudo selectors from most of the icon classes (not need by button tool anymore, makes them more reusable now)
ve.ui.Tool.css
* Adjusted drop down tool styles so menu appears below, instead
of on top, of the label
* Adjusted paragraph font size to better match actual content
* Updated class names to still work with menu widget changes
(items are their own widgets now)
* Updated selectors as per changes in the structure of button tools
ve.ui.Widget.css
* Added styles for buttons and menu items
* Adjusted menu styles
ve.ui.*ButtonTool.js
* Added config options argument passthrough
ve.ui.ButtonTool.js
* Moved var statement to the top inside constructor
* Switched to using "a" tag to get cross-browser :active support
* Added icon to inside of button to make icon styles more reusable
* Removed disabled support (now provided by widget parent class)
ve.ui.FormatDropDownTool.js
* Updated options initialization to construct menu item objects
* Modified handling of items to account for changes in menu and
item classes
* Optimized onUpdateState method a bit, adding early exit to
inner loop
ve.ui.ButtonTool.js, ve.ui.DropdownTool.js, ve.ui.Context.js,
ve.ui.Frame, ve.ui.Tool.js, ve.ui.Widget.js
* Added chain ability to non-getter methods
ve.ui.DropdownTool.js
* Removed items argument to constructor
* Updated code as per changes in menu class
* Fixed inconsistent naming of event handler methods
* Removed item event handling (now handled by items directly)
* Made use of this.$$ to ensure tool works in other frames
ve.ui.Tool.js
* Made tools inherit from widget
* Moved trigger registry event handler to a method
ve.ui.Context.js
* Switched from using menu to contain toolbar to a simple wrapper
ve.ui.js
* Added get$$ method, a convenience function for binding jQuery
to a specific document context
ve.ui.*Widget.js
* Switched to using a config options object instead of individual arguments
* Added options
* Factored out flags and labels into their own classes
* Refactored value setting methods for inputs
ve.ui.MenuWidget.js, ve.ui.MenuItemWidget.js
* Broke items out into their own classes
* Redesigned API
* Updated code that uses these classes
* Added support for keyboard interaction
* Made items flash when selected (delaying the hiding of the menu for 200ms)
ve.ui.LinkTargetInputWidget.js, ve.ui.MWLinkTargetInputWidget
* Refactored annotation setting methods
Change-Id: I7769bd5a5b79f1ab36f258ef9f2be583ca503ce6
2013-02-20 23:25:12 +00:00
|
|
|
* @param {jQuery.Event} e Key up event
|
2013-10-22 17:54:59 +00:00
|
|
|
* @fires selectionEnd
|
2013-01-16 21:51:05 +00:00
|
|
|
*/
|
|
|
|
ve.ce.Surface.prototype.onDocumentKeyUp = function ( e ) {
|
|
|
|
// Detect end of selecting by letting go of shift
|
2013-10-09 20:09:59 +00:00
|
|
|
if ( !this.dragging && this.selecting && e.keyCode === OO.ui.Keys.SHIFT ) {
|
2013-01-16 21:51:05 +00:00
|
|
|
this.selecting = false;
|
|
|
|
this.emit( 'selectionEnd' );
|
2012-06-29 00:26:10 +00:00
|
|
|
}
|
|
|
|
};
|
2012-06-20 01:20:28 +00:00
|
|
|
|
Make use of new jshint options
* Restricting "camelcase":
No changes, we were passing all of these already
* Explicitly unrestricting "forin" and "plusplus"
These are off by default in node-jshint, but some distro of jshint
and editors that use their own wrapper around jshint instead of
node-jshint (Eclipse?) may have different defaults. Therefor
setting them to false explicitly. This also serves as a reminder
for the future so we'll always know we don't pass that, in case
we would want to change that.
* Fix order ("quotemark" before "regexp")
* Restricting "unused"
We're not passing all of this, which is why I've set it to false
for now. But I did put it in .jshintrc as placeholder.
I've fixed most of them, there's some left where there is no clean
solution.
* While at it fix a few issues:
- Unused variables ($target, $window)
- Bad practices (using jQuery context for find instead of creation)
- Redundant /*global */ comments
- Parameters that are not used and don't have documentation either
- Lines longer than 100 chars @ 4 spaces/tab
* Note:
- ve.ce.Surface.prototype.onChange takes two arguments but never
uses the former. And even the second one can be null/undefined.
Aside from that, the .change() function emits
another event for the transaction already. Looks like this
should be refactored a bit, two more separated events probably
or one that is actually used better.
- Also cleaned up a lot of comments, some of which were missing,
others were incorrect
- Reworked the contentChange event so we are no longer using the
word new as an object key; expanded a complex object into multiple
arguments being passed through the event to make it easier to work
with and document
Change-Id: I8490815a508c6c379d5f9a743bb4aefd14576aa6
2012-08-07 06:02:18 +00:00
|
|
|
/**
|
2013-01-15 23:38:49 +00:00
|
|
|
* Handle cut events.
|
Make use of new jshint options
* Restricting "camelcase":
No changes, we were passing all of these already
* Explicitly unrestricting "forin" and "plusplus"
These are off by default in node-jshint, but some distro of jshint
and editors that use their own wrapper around jshint instead of
node-jshint (Eclipse?) may have different defaults. Therefor
setting them to false explicitly. This also serves as a reminder
for the future so we'll always know we don't pass that, in case
we would want to change that.
* Fix order ("quotemark" before "regexp")
* Restricting "unused"
We're not passing all of this, which is why I've set it to false
for now. But I did put it in .jshintrc as placeholder.
I've fixed most of them, there's some left where there is no clean
solution.
* While at it fix a few issues:
- Unused variables ($target, $window)
- Bad practices (using jQuery context for find instead of creation)
- Redundant /*global */ comments
- Parameters that are not used and don't have documentation either
- Lines longer than 100 chars @ 4 spaces/tab
* Note:
- ve.ce.Surface.prototype.onChange takes two arguments but never
uses the former. And even the second one can be null/undefined.
Aside from that, the .change() function emits
another event for the transaction already. Looks like this
should be refactored a bit, two more separated events probably
or one that is actually used better.
- Also cleaned up a lot of comments, some of which were missing,
others were incorrect
- Reworked the contentChange event so we are no longer using the
word new as an object key; expanded a complex object into multiple
arguments being passed through the event to make it easier to work
with and document
Change-Id: I8490815a508c6c379d5f9a743bb4aefd14576aa6
2012-08-07 06:02:18 +00:00
|
|
|
*
|
|
|
|
* @method
|
Major UI refactoring and improvements
Objective:
Refactor UI widgets, improve usability and accessibility of menus, general cleanup and style improvements.
Extras:
Fixed documentation in a few other files to make descriptions of jQuery event arguments more consistent, classes inherit correctly, and made use of the @cfg functionality in jsduck.
Changes:
.docs/config.json
* Added window, HTMLDocument, HTMLElement, DocumentFragment and XMLHttpRequest to externals, so jsduck doesn't throw warnings when they are used
demos/ve/index.php, modules/ve/test/index.php, VisualEditor.php
* Moved widgets above tools (since tools use widgets)
demos/ve/index.php
* Refactored widget initialization to use options
* Renamed variables to match widget names
ve.init.mw.ViewPageTarget.css
* Adjusted text sizes to make widgets work normally
* Added margins for buttons in toolbar (since button widgets
don't have any)
* Removed styles for init buttons (button widgets now)
ve.init.mw.ViewPageTarget.js
* Switched to using button widgets (involved moving things around
a bit)
ve.ui.LinkInspector.js, ve.ui.MWLinkInspector.js
* Renamed static property "inputWidget" to
"linkTargetInputWidget" to better reflect the required base class
for the properties value
icons.ai, check.png, check.svg
* Added "check" icon, used in menu right now to show which item
is selected
ve.ui.Icons-raster.css, ve.ui.Icons-vector.css
* Added check icon
* Removed :before pseudo selectors from most of the icon classes (not need by button tool anymore, makes them more reusable now)
ve.ui.Tool.css
* Adjusted drop down tool styles so menu appears below, instead
of on top, of the label
* Adjusted paragraph font size to better match actual content
* Updated class names to still work with menu widget changes
(items are their own widgets now)
* Updated selectors as per changes in the structure of button tools
ve.ui.Widget.css
* Added styles for buttons and menu items
* Adjusted menu styles
ve.ui.*ButtonTool.js
* Added config options argument passthrough
ve.ui.ButtonTool.js
* Moved var statement to the top inside constructor
* Switched to using "a" tag to get cross-browser :active support
* Added icon to inside of button to make icon styles more reusable
* Removed disabled support (now provided by widget parent class)
ve.ui.FormatDropDownTool.js
* Updated options initialization to construct menu item objects
* Modified handling of items to account for changes in menu and
item classes
* Optimized onUpdateState method a bit, adding early exit to
inner loop
ve.ui.ButtonTool.js, ve.ui.DropdownTool.js, ve.ui.Context.js,
ve.ui.Frame, ve.ui.Tool.js, ve.ui.Widget.js
* Added chain ability to non-getter methods
ve.ui.DropdownTool.js
* Removed items argument to constructor
* Updated code as per changes in menu class
* Fixed inconsistent naming of event handler methods
* Removed item event handling (now handled by items directly)
* Made use of this.$$ to ensure tool works in other frames
ve.ui.Tool.js
* Made tools inherit from widget
* Moved trigger registry event handler to a method
ve.ui.Context.js
* Switched from using menu to contain toolbar to a simple wrapper
ve.ui.js
* Added get$$ method, a convenience function for binding jQuery
to a specific document context
ve.ui.*Widget.js
* Switched to using a config options object instead of individual arguments
* Added options
* Factored out flags and labels into their own classes
* Refactored value setting methods for inputs
ve.ui.MenuWidget.js, ve.ui.MenuItemWidget.js
* Broke items out into their own classes
* Redesigned API
* Updated code that uses these classes
* Added support for keyboard interaction
* Made items flash when selected (delaying the hiding of the menu for 200ms)
ve.ui.LinkTargetInputWidget.js, ve.ui.MWLinkTargetInputWidget
* Refactored annotation setting methods
Change-Id: I7769bd5a5b79f1ab36f258ef9f2be583ca503ce6
2013-02-20 23:25:12 +00:00
|
|
|
* @param {jQuery.Event} e Cut event
|
Make use of new jshint options
* Restricting "camelcase":
No changes, we were passing all of these already
* Explicitly unrestricting "forin" and "plusplus"
These are off by default in node-jshint, but some distro of jshint
and editors that use their own wrapper around jshint instead of
node-jshint (Eclipse?) may have different defaults. Therefor
setting them to false explicitly. This also serves as a reminder
for the future so we'll always know we don't pass that, in case
we would want to change that.
* Fix order ("quotemark" before "regexp")
* Restricting "unused"
We're not passing all of this, which is why I've set it to false
for now. But I did put it in .jshintrc as placeholder.
I've fixed most of them, there's some left where there is no clean
solution.
* While at it fix a few issues:
- Unused variables ($target, $window)
- Bad practices (using jQuery context for find instead of creation)
- Redundant /*global */ comments
- Parameters that are not used and don't have documentation either
- Lines longer than 100 chars @ 4 spaces/tab
* Note:
- ve.ce.Surface.prototype.onChange takes two arguments but never
uses the former. And even the second one can be null/undefined.
Aside from that, the .change() function emits
another event for the transaction already. Looks like this
should be refactored a bit, two more separated events probably
or one that is actually used better.
- Also cleaned up a lot of comments, some of which were missing,
others were incorrect
- Reworked the contentChange event so we are no longer using the
word new as an object key; expanded a complex object into multiple
arguments being passed through the event to make it easier to work
with and document
Change-Id: I8490815a508c6c379d5f9a743bb4aefd14576aa6
2012-08-07 06:02:18 +00:00
|
|
|
*/
|
Kranitor #1: On-boarding
'''Kranitor commits''' are commits by Krinkle with his janitor hat on.
Must never contain functional changes mixed with miscellaneous changes.
.gitignore:
* Add .DS_Store to the ignore list so that browsing the directories
on Mac OS X, will not add these files to the list of untracked
files.
* Fix missing newline at end of file
.jshintrc
* raises -> throws
* +module (QUnit.module)
* remove 'Node' (as of node-jshint 1.7.2 this is now part of
'browser:true', as it should be)
Authors:
* Adding myself
MWExtension/VisualEditor.php
* Fix default value of wgVisualEditorParsoidURL to not
point to the experimental instance in WMF Labs.
Issues:
* ve.ce.TextNode:
- Fix TODO: Don't perform a useless clone of an already-jQuerified object.
- Use .html() to set html content instead of encapsulating between
two strings. This is slightly faster but more importantly safer,
and prevents situations where the resulting jQuery collection
actually contains 2 elements instead of 1, thus messing up
what .contents() is iterating over.
* ve.ce.Document.test.js
- Fix: ReferenceError: assert is not defined
* ve.dm.Document.test.js
- Fix: ReferenceError: assert is not defined
* ve.dm.Transaction.test.js
- Fix: ReferenceError: assert is not defined
* ve.dm.TransactionProcessor.test.js
- Fix: ReferenceError: assert is not defined
* ext.visualEditor.viewPageTarget
- Missing dependency on 'mediawiki.Title'
Code conventions / Misc cleanup
* Various JSHint warnings.
* Whitespace
* jQuery(): Use '<tag>' for element creation,
use '<valid><xml/></valid>' for parsing
* Use the default operator instead of ternary when the condition and
first value are the same.
x = foo ? foo : bar; -> x = foo || bar;
Because contrary to some programming language (PHP...), in JS the
default operator does not enforce a boolean result but returns the
original value, hence it being called the 'default' operator, as
opposed to the 'or' operator.
* No need to call addClass() twice, it takes a space-separated list
(jQuery splits by space and adds if needed)
* Use .on( event[, selector], fn ) instead of the deprecated
routers to it such as .bind(), .delegate() and .live().
All these three are now built-in and fully compatible with .on()
* Add 'XXX:' comments for suspicious code that I don't want to change
as part of a clean up commit.
* Remove unused variables (several var x = this; where x was not
used anywhere, possibly from boilerplate copy/paste)
* Follows-up Trevor's commit that converts test suites to the new
QUnit format. Also removed the globals since we no longer use those
any more.
Change-Id: I7e37c9bff812e371c7f65a6fd85d9e2af3e0a22f
2012-07-27 08:43:33 +00:00
|
|
|
ve.ce.Surface.prototype.onCut = function ( e ) {
|
2013-09-07 01:03:10 +00:00
|
|
|
// TODO: no pollOnce here: but should we add one?
|
|
|
|
this.surfaceObserver.stopTimerLoop();
|
2012-06-29 00:26:10 +00:00
|
|
|
this.onCopy( e );
|
2013-02-19 22:14:41 +00:00
|
|
|
setTimeout( ve.bind( function () {
|
|
|
|
var selection, tx;
|
2012-06-27 16:29:58 +00:00
|
|
|
|
2012-06-29 00:26:10 +00:00
|
|
|
// We don't like how browsers cut, so let's undo it and do it ourselves.
|
The Great ve.ui.Surface refactor of 2013
Prologue:
Farewell ve.Editor my good chap… Oh, hey there HTML frames - I didn't
see you there! In a world where iframes are outlaws, and symbols like
document and window are global, there were more than a few assumptions
about which document or window was being used. But fear not - for this
commit (probably) tracks them all down, leaving a trail of
iframe-compatible awesomeness in its wake. With the great ve.ui.Surface
now able to be used inside of iframes, let the reference editing
commence. But there, lurking in the darkness is a DM issue so fierce it
may take Roan and/or Ed up to 3 whole hours to sort it out.
Note to Roan and/or Ed:
Editing references seems to work fine, but when saving the page there
are "no changes" which is a reasonable indication to the contrary.
Objectives:
* Make it possible to have multiple surfaces be instantiated, get along
nicely, and be embedded inside of iframes if needed.
* Make reference content editable within a dialog
Approach:
* Move what's left of ve.Editor to ve.ui.Surface and essentially
obliterate all use of it
* Make even more stuff inherit from ve.Element (long live this.$$)
* Use the correct document or window anywhere it was being assumed to be
the top level one
* Resolve stacking order issues by removing the excessive use of z-index
and introducing global and local overlay elements for each editor
* Add a surface to the reference dialog, load up the reference contents
and save them back on apply
* Actually destroy what we create in ce and ui surfaces
* Add recursive frame offset calculation method to ve.Element
* Moved ve.ce.Surface's getSelectionRect method to the prototype
Bonus:
* Move ve.ce.DocumentNode.css contents to ve.ce.Node.css (not sure why it
was separate in the first place, but I'm likely the one to blame)
* Fix blatant lies in documentation
* Whitespace cleanup here and there
* Get rid of ve.ui.Window overlays - not used or needed
Change-Id: Iede83e7d24f7cb249b6ba3dc45d770445b862e08
2013-05-20 22:45:50 +00:00
|
|
|
this.$document[0].execCommand( 'undo', false, false );
|
2013-02-19 22:14:41 +00:00
|
|
|
selection = this.model.getSelection();
|
2012-06-29 00:26:10 +00:00
|
|
|
|
|
|
|
// Transact
|
2013-02-19 22:14:41 +00:00
|
|
|
tx = ve.dm.Transaction.newFromRemoval( this.documentView.model, selection );
|
2012-06-29 00:26:10 +00:00
|
|
|
|
2013-08-26 18:39:25 +00:00
|
|
|
// Document may not have had real focus (e.g. with a FocusableNode)
|
2013-12-04 19:42:44 +00:00
|
|
|
this.documentView.getDocumentNode().$element[0].focus();
|
2013-08-26 18:39:25 +00:00
|
|
|
|
2013-02-19 22:14:41 +00:00
|
|
|
this.model.change( tx, new ve.Range( selection.start ) );
|
|
|
|
this.surfaceObserver.clear();
|
2013-09-07 01:03:10 +00:00
|
|
|
this.surfaceObserver.startTimerLoop();
|
|
|
|
this.surfaceObserver.pollOnce();
|
2013-02-26 00:16:57 +00:00
|
|
|
}, this ) );
|
2012-06-20 01:20:28 +00:00
|
|
|
};
|
2012-04-06 15:10:30 +00:00
|
|
|
|
2013-01-16 21:51:05 +00:00
|
|
|
/**
|
|
|
|
* Handle copy events.
|
|
|
|
*
|
|
|
|
* @method
|
Major UI refactoring and improvements
Objective:
Refactor UI widgets, improve usability and accessibility of menus, general cleanup and style improvements.
Extras:
Fixed documentation in a few other files to make descriptions of jQuery event arguments more consistent, classes inherit correctly, and made use of the @cfg functionality in jsduck.
Changes:
.docs/config.json
* Added window, HTMLDocument, HTMLElement, DocumentFragment and XMLHttpRequest to externals, so jsduck doesn't throw warnings when they are used
demos/ve/index.php, modules/ve/test/index.php, VisualEditor.php
* Moved widgets above tools (since tools use widgets)
demos/ve/index.php
* Refactored widget initialization to use options
* Renamed variables to match widget names
ve.init.mw.ViewPageTarget.css
* Adjusted text sizes to make widgets work normally
* Added margins for buttons in toolbar (since button widgets
don't have any)
* Removed styles for init buttons (button widgets now)
ve.init.mw.ViewPageTarget.js
* Switched to using button widgets (involved moving things around
a bit)
ve.ui.LinkInspector.js, ve.ui.MWLinkInspector.js
* Renamed static property "inputWidget" to
"linkTargetInputWidget" to better reflect the required base class
for the properties value
icons.ai, check.png, check.svg
* Added "check" icon, used in menu right now to show which item
is selected
ve.ui.Icons-raster.css, ve.ui.Icons-vector.css
* Added check icon
* Removed :before pseudo selectors from most of the icon classes (not need by button tool anymore, makes them more reusable now)
ve.ui.Tool.css
* Adjusted drop down tool styles so menu appears below, instead
of on top, of the label
* Adjusted paragraph font size to better match actual content
* Updated class names to still work with menu widget changes
(items are their own widgets now)
* Updated selectors as per changes in the structure of button tools
ve.ui.Widget.css
* Added styles for buttons and menu items
* Adjusted menu styles
ve.ui.*ButtonTool.js
* Added config options argument passthrough
ve.ui.ButtonTool.js
* Moved var statement to the top inside constructor
* Switched to using "a" tag to get cross-browser :active support
* Added icon to inside of button to make icon styles more reusable
* Removed disabled support (now provided by widget parent class)
ve.ui.FormatDropDownTool.js
* Updated options initialization to construct menu item objects
* Modified handling of items to account for changes in menu and
item classes
* Optimized onUpdateState method a bit, adding early exit to
inner loop
ve.ui.ButtonTool.js, ve.ui.DropdownTool.js, ve.ui.Context.js,
ve.ui.Frame, ve.ui.Tool.js, ve.ui.Widget.js
* Added chain ability to non-getter methods
ve.ui.DropdownTool.js
* Removed items argument to constructor
* Updated code as per changes in menu class
* Fixed inconsistent naming of event handler methods
* Removed item event handling (now handled by items directly)
* Made use of this.$$ to ensure tool works in other frames
ve.ui.Tool.js
* Made tools inherit from widget
* Moved trigger registry event handler to a method
ve.ui.Context.js
* Switched from using menu to contain toolbar to a simple wrapper
ve.ui.js
* Added get$$ method, a convenience function for binding jQuery
to a specific document context
ve.ui.*Widget.js
* Switched to using a config options object instead of individual arguments
* Added options
* Factored out flags and labels into their own classes
* Refactored value setting methods for inputs
ve.ui.MenuWidget.js, ve.ui.MenuItemWidget.js
* Broke items out into their own classes
* Redesigned API
* Updated code that uses these classes
* Added support for keyboard interaction
* Made items flash when selected (delaying the hiding of the menu for 200ms)
ve.ui.LinkTargetInputWidget.js, ve.ui.MWLinkTargetInputWidget
* Refactored annotation setting methods
Change-Id: I7769bd5a5b79f1ab36f258ef9f2be583ca503ce6
2013-02-20 23:25:12 +00:00
|
|
|
* @param {jQuery.Event} e Copy event
|
2013-01-16 21:51:05 +00:00
|
|
|
*/
|
2013-08-21 21:00:48 +00:00
|
|
|
ve.ce.Surface.prototype.onCopy = function ( e ) {
|
2013-09-07 09:32:05 +00:00
|
|
|
var rangyRange, sel, originalRange,
|
2013-09-30 13:26:33 +00:00
|
|
|
clipboardIndex, clipboardItem, pasteData,
|
2013-09-07 09:32:05 +00:00
|
|
|
scrollTop,
|
|
|
|
view = this,
|
2013-09-30 13:26:33 +00:00
|
|
|
slice = this.model.documentModel.cloneSliceFromRange( this.model.getSelection() ),
|
2013-08-21 21:00:48 +00:00
|
|
|
clipboardData = e.originalEvent.clipboardData,
|
2013-11-01 19:45:59 +00:00
|
|
|
$window = this.$( OO.ui.Element.getWindow( this.$.context ) );
|
2013-01-16 21:51:05 +00:00
|
|
|
|
2013-09-07 09:32:05 +00:00
|
|
|
this.$pasteTarget.empty();
|
|
|
|
|
2013-09-30 13:26:33 +00:00
|
|
|
pasteData = slice.data.clone();
|
|
|
|
|
2013-12-11 10:33:15 +00:00
|
|
|
// Clone the elements in the slice
|
|
|
|
slice.data.cloneElements();
|
|
|
|
|
2013-09-30 13:26:33 +00:00
|
|
|
ve.dm.converter.store = slice.getStore();
|
|
|
|
ve.dm.converter.internalList = slice.getInternalList();
|
2013-10-03 11:32:02 +00:00
|
|
|
ve.dm.converter.getDomSubtreeFromData( slice.getData(), this.$pasteTarget[0] );
|
2013-09-07 09:32:05 +00:00
|
|
|
|
2013-09-30 13:26:33 +00:00
|
|
|
// Some browsers strip out spans when they match the styling of the
|
|
|
|
// paste target (e.g. plain spans) so we must protect against this
|
|
|
|
// by adding a dummy class, which we can remove after paste.
|
|
|
|
this.$pasteTarget.find( 'span' ).addClass( 've-pasteProtect' );
|
|
|
|
|
|
|
|
clipboardItem = { 'slice': slice, 'hash': null };
|
2013-09-07 09:32:05 +00:00
|
|
|
clipboardIndex = this.clipboard.push( clipboardItem ) - 1;
|
|
|
|
|
2013-08-21 21:00:48 +00:00
|
|
|
// Check we have setData and that it actually works (returns true)
|
2013-09-07 09:32:05 +00:00
|
|
|
if (
|
|
|
|
clipboardData && clipboardData.setData &&
|
|
|
|
clipboardData.setData( 'text/xcustom', '' ) &&
|
|
|
|
clipboardData.setData( 'text/html', '' )
|
|
|
|
) {
|
|
|
|
// Webkit allows us to directly edit the clipboard
|
|
|
|
// Disable the default event so we can override the data
|
2013-08-21 21:00:48 +00:00
|
|
|
e.preventDefault();
|
2013-09-07 09:32:05 +00:00
|
|
|
clipboardData.setData( 'text/xcustom', this.clipboardId + '-' + clipboardIndex );
|
2013-08-21 21:00:48 +00:00
|
|
|
// As we've disabled the default event we need to set the normal clipboard data
|
2013-09-07 09:32:05 +00:00
|
|
|
clipboardData.setData( 'text/html', this.$pasteTarget.html() );
|
|
|
|
clipboardData.setData( 'text/plain', this.$pasteTarget.text() );
|
2013-08-21 21:00:48 +00:00
|
|
|
} else {
|
2013-09-30 13:26:33 +00:00
|
|
|
clipboardItem.hash = this.constructor.static.getClipboardHash( this.$pasteTarget.contents() );
|
2013-09-07 09:32:05 +00:00
|
|
|
this.$pasteTarget.prepend(
|
2013-11-01 19:45:59 +00:00
|
|
|
this.$( '<span>' ).attr( 'data-ve-clipboard-key', this.clipboardId + '-' + clipboardIndex )
|
2013-09-07 09:32:05 +00:00
|
|
|
);
|
|
|
|
// If direct clipboard editing is not allowed, we must use the pasteTarget to
|
|
|
|
// select the data we want to go in the clipboard
|
|
|
|
rangyRange = rangy.createRange( this.getElementDocument() );
|
|
|
|
rangyRange.setStart( this.$pasteTarget[0], 0 );
|
|
|
|
rangyRange.setEnd( this.$pasteTarget[0], this.$pasteTarget[0].childNodes.length );
|
|
|
|
|
|
|
|
// Save scroll position before changing focus to "offscreen" paste target
|
|
|
|
scrollTop = $window.scrollTop();
|
|
|
|
|
|
|
|
sel = rangy.getSelection( this.getElementDocument() );
|
|
|
|
originalRange = sel.getRangeAt( 0 ).cloneRange();
|
|
|
|
sel.removeAllRanges();
|
|
|
|
this.$pasteTarget[0].focus();
|
|
|
|
sel.addRange( rangyRange, false );
|
|
|
|
|
|
|
|
setTimeout( function () {
|
|
|
|
sel = rangy.getSelection( view.getElementDocument() );
|
|
|
|
sel.removeAllRanges();
|
2013-12-04 19:42:44 +00:00
|
|
|
view.documentView.getDocumentNode().$element[0].focus();
|
2013-09-07 09:32:05 +00:00
|
|
|
sel.addRange( originalRange );
|
|
|
|
|
|
|
|
$window.scrollTop( scrollTop );
|
|
|
|
} );
|
2013-08-21 21:00:48 +00:00
|
|
|
}
|
2013-01-16 21:51:05 +00:00
|
|
|
};
|
|
|
|
|
Make use of new jshint options
* Restricting "camelcase":
No changes, we were passing all of these already
* Explicitly unrestricting "forin" and "plusplus"
These are off by default in node-jshint, but some distro of jshint
and editors that use their own wrapper around jshint instead of
node-jshint (Eclipse?) may have different defaults. Therefor
setting them to false explicitly. This also serves as a reminder
for the future so we'll always know we don't pass that, in case
we would want to change that.
* Fix order ("quotemark" before "regexp")
* Restricting "unused"
We're not passing all of this, which is why I've set it to false
for now. But I did put it in .jshintrc as placeholder.
I've fixed most of them, there's some left where there is no clean
solution.
* While at it fix a few issues:
- Unused variables ($target, $window)
- Bad practices (using jQuery context for find instead of creation)
- Redundant /*global */ comments
- Parameters that are not used and don't have documentation either
- Lines longer than 100 chars @ 4 spaces/tab
* Note:
- ve.ce.Surface.prototype.onChange takes two arguments but never
uses the former. And even the second one can be null/undefined.
Aside from that, the .change() function emits
another event for the transaction already. Looks like this
should be refactored a bit, two more separated events probably
or one that is actually used better.
- Also cleaned up a lot of comments, some of which were missing,
others were incorrect
- Reworked the contentChange event so we are no longer using the
word new as an object key; expanded a complex object into multiple
arguments being passed through the event to make it easier to work
with and document
Change-Id: I8490815a508c6c379d5f9a743bb4aefd14576aa6
2012-08-07 06:02:18 +00:00
|
|
|
/**
|
2013-09-07 09:32:05 +00:00
|
|
|
* Handle native paste event
|
Make use of new jshint options
* Restricting "camelcase":
No changes, we were passing all of these already
* Explicitly unrestricting "forin" and "plusplus"
These are off by default in node-jshint, but some distro of jshint
and editors that use their own wrapper around jshint instead of
node-jshint (Eclipse?) may have different defaults. Therefor
setting them to false explicitly. This also serves as a reminder
for the future so we'll always know we don't pass that, in case
we would want to change that.
* Fix order ("quotemark" before "regexp")
* Restricting "unused"
We're not passing all of this, which is why I've set it to false
for now. But I did put it in .jshintrc as placeholder.
I've fixed most of them, there's some left where there is no clean
solution.
* While at it fix a few issues:
- Unused variables ($target, $window)
- Bad practices (using jQuery context for find instead of creation)
- Redundant /*global */ comments
- Parameters that are not used and don't have documentation either
- Lines longer than 100 chars @ 4 spaces/tab
* Note:
- ve.ce.Surface.prototype.onChange takes two arguments but never
uses the former. And even the second one can be null/undefined.
Aside from that, the .change() function emits
another event for the transaction already. Looks like this
should be refactored a bit, two more separated events probably
or one that is actually used better.
- Also cleaned up a lot of comments, some of which were missing,
others were incorrect
- Reworked the contentChange event so we are no longer using the
word new as an object key; expanded a complex object into multiple
arguments being passed through the event to make it easier to work
with and document
Change-Id: I8490815a508c6c379d5f9a743bb4aefd14576aa6
2012-08-07 06:02:18 +00:00
|
|
|
*
|
Major UI refactoring and improvements
Objective:
Refactor UI widgets, improve usability and accessibility of menus, general cleanup and style improvements.
Extras:
Fixed documentation in a few other files to make descriptions of jQuery event arguments more consistent, classes inherit correctly, and made use of the @cfg functionality in jsduck.
Changes:
.docs/config.json
* Added window, HTMLDocument, HTMLElement, DocumentFragment and XMLHttpRequest to externals, so jsduck doesn't throw warnings when they are used
demos/ve/index.php, modules/ve/test/index.php, VisualEditor.php
* Moved widgets above tools (since tools use widgets)
demos/ve/index.php
* Refactored widget initialization to use options
* Renamed variables to match widget names
ve.init.mw.ViewPageTarget.css
* Adjusted text sizes to make widgets work normally
* Added margins for buttons in toolbar (since button widgets
don't have any)
* Removed styles for init buttons (button widgets now)
ve.init.mw.ViewPageTarget.js
* Switched to using button widgets (involved moving things around
a bit)
ve.ui.LinkInspector.js, ve.ui.MWLinkInspector.js
* Renamed static property "inputWidget" to
"linkTargetInputWidget" to better reflect the required base class
for the properties value
icons.ai, check.png, check.svg
* Added "check" icon, used in menu right now to show which item
is selected
ve.ui.Icons-raster.css, ve.ui.Icons-vector.css
* Added check icon
* Removed :before pseudo selectors from most of the icon classes (not need by button tool anymore, makes them more reusable now)
ve.ui.Tool.css
* Adjusted drop down tool styles so menu appears below, instead
of on top, of the label
* Adjusted paragraph font size to better match actual content
* Updated class names to still work with menu widget changes
(items are their own widgets now)
* Updated selectors as per changes in the structure of button tools
ve.ui.Widget.css
* Added styles for buttons and menu items
* Adjusted menu styles
ve.ui.*ButtonTool.js
* Added config options argument passthrough
ve.ui.ButtonTool.js
* Moved var statement to the top inside constructor
* Switched to using "a" tag to get cross-browser :active support
* Added icon to inside of button to make icon styles more reusable
* Removed disabled support (now provided by widget parent class)
ve.ui.FormatDropDownTool.js
* Updated options initialization to construct menu item objects
* Modified handling of items to account for changes in menu and
item classes
* Optimized onUpdateState method a bit, adding early exit to
inner loop
ve.ui.ButtonTool.js, ve.ui.DropdownTool.js, ve.ui.Context.js,
ve.ui.Frame, ve.ui.Tool.js, ve.ui.Widget.js
* Added chain ability to non-getter methods
ve.ui.DropdownTool.js
* Removed items argument to constructor
* Updated code as per changes in menu class
* Fixed inconsistent naming of event handler methods
* Removed item event handling (now handled by items directly)
* Made use of this.$$ to ensure tool works in other frames
ve.ui.Tool.js
* Made tools inherit from widget
* Moved trigger registry event handler to a method
ve.ui.Context.js
* Switched from using menu to contain toolbar to a simple wrapper
ve.ui.js
* Added get$$ method, a convenience function for binding jQuery
to a specific document context
ve.ui.*Widget.js
* Switched to using a config options object instead of individual arguments
* Added options
* Factored out flags and labels into their own classes
* Refactored value setting methods for inputs
ve.ui.MenuWidget.js, ve.ui.MenuItemWidget.js
* Broke items out into their own classes
* Redesigned API
* Updated code that uses these classes
* Added support for keyboard interaction
* Made items flash when selected (delaying the hiding of the menu for 200ms)
ve.ui.LinkTargetInputWidget.js, ve.ui.MWLinkTargetInputWidget
* Refactored annotation setting methods
Change-Id: I7769bd5a5b79f1ab36f258ef9f2be583ca503ce6
2013-02-20 23:25:12 +00:00
|
|
|
* @param {jQuery.Event} e Paste event
|
Make use of new jshint options
* Restricting "camelcase":
No changes, we were passing all of these already
* Explicitly unrestricting "forin" and "plusplus"
These are off by default in node-jshint, but some distro of jshint
and editors that use their own wrapper around jshint instead of
node-jshint (Eclipse?) may have different defaults. Therefor
setting them to false explicitly. This also serves as a reminder
for the future so we'll always know we don't pass that, in case
we would want to change that.
* Fix order ("quotemark" before "regexp")
* Restricting "unused"
We're not passing all of this, which is why I've set it to false
for now. But I did put it in .jshintrc as placeholder.
I've fixed most of them, there's some left where there is no clean
solution.
* While at it fix a few issues:
- Unused variables ($target, $window)
- Bad practices (using jQuery context for find instead of creation)
- Redundant /*global */ comments
- Parameters that are not used and don't have documentation either
- Lines longer than 100 chars @ 4 spaces/tab
* Note:
- ve.ce.Surface.prototype.onChange takes two arguments but never
uses the former. And even the second one can be null/undefined.
Aside from that, the .change() function emits
another event for the transaction already. Looks like this
should be refactored a bit, two more separated events probably
or one that is actually used better.
- Also cleaned up a lot of comments, some of which were missing,
others were incorrect
- Reworked the contentChange event so we are no longer using the
word new as an object key; expanded a complex object into multiple
arguments being passed through the event to make it easier to work
with and document
Change-Id: I8490815a508c6c379d5f9a743bb4aefd14576aa6
2012-08-07 06:02:18 +00:00
|
|
|
*/
|
2013-08-21 21:00:48 +00:00
|
|
|
ve.ce.Surface.prototype.onPaste = function ( e ) {
|
2012-12-07 22:58:29 +00:00
|
|
|
// Prevent pasting until after we are done
|
|
|
|
if ( this.pasting ) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
this.pasting = true;
|
2013-09-07 09:32:05 +00:00
|
|
|
this.beforePaste( e );
|
2013-12-11 19:22:42 +00:00
|
|
|
setTimeout( ve.bind( function () {
|
|
|
|
this.afterPaste( e );
|
|
|
|
|
|
|
|
// Allow pasting again
|
|
|
|
this.pasting = false;
|
|
|
|
this.pasteSpecial = false;
|
|
|
|
this.beforePasteData = null;
|
|
|
|
}, this ) );
|
2013-09-07 09:32:05 +00:00
|
|
|
};
|
2012-12-07 22:58:29 +00:00
|
|
|
|
2013-09-07 09:32:05 +00:00
|
|
|
/**
|
|
|
|
* Handle pre-paste events.
|
|
|
|
*
|
|
|
|
* @param {jQuery.Event} e Paste event
|
|
|
|
*/
|
|
|
|
ve.ce.Surface.prototype.beforePaste = function ( e ) {
|
2013-09-30 13:26:33 +00:00
|
|
|
var tx, node, range, rangyRange, sel,
|
|
|
|
context, leftText, rightText, textNode, textStart, textEnd,
|
2013-11-01 19:45:59 +00:00
|
|
|
$window = this.$( OO.ui.Element.getWindow( this.$.context ) ),
|
2013-08-21 21:00:48 +00:00
|
|
|
selection = this.model.getSelection(),
|
2013-09-30 13:26:33 +00:00
|
|
|
clipboardData = e.originalEvent.clipboardData,
|
|
|
|
doc = this.model.documentModel;
|
2013-09-07 09:32:05 +00:00
|
|
|
|
|
|
|
this.beforePasteData = {};
|
|
|
|
if ( clipboardData ) {
|
|
|
|
this.beforePasteData.custom = clipboardData.getData( 'text/xcustom' );
|
|
|
|
this.beforePasteData.html = clipboardData.getData( 'text/html' );
|
|
|
|
}
|
2012-06-27 16:29:58 +00:00
|
|
|
|
2013-09-07 01:03:10 +00:00
|
|
|
// TODO: no pollOnce here: but should we add one?
|
|
|
|
this.surfaceObserver.stopTimerLoop();
|
2012-06-27 16:29:58 +00:00
|
|
|
|
2012-06-20 01:20:28 +00:00
|
|
|
// Pasting into a range? Remove first.
|
The Great ve.ui.Surface refactor of 2013
Prologue:
Farewell ve.Editor my good chap… Oh, hey there HTML frames - I didn't
see you there! In a world where iframes are outlaws, and symbols like
document and window are global, there were more than a few assumptions
about which document or window was being used. But fear not - for this
commit (probably) tracks them all down, leaving a trail of
iframe-compatible awesomeness in its wake. With the great ve.ui.Surface
now able to be used inside of iframes, let the reference editing
commence. But there, lurking in the darkness is a DM issue so fierce it
may take Roan and/or Ed up to 3 whole hours to sort it out.
Note to Roan and/or Ed:
Editing references seems to work fine, but when saving the page there
are "no changes" which is a reasonable indication to the contrary.
Objectives:
* Make it possible to have multiple surfaces be instantiated, get along
nicely, and be embedded inside of iframes if needed.
* Make reference content editable within a dialog
Approach:
* Move what's left of ve.Editor to ve.ui.Surface and essentially
obliterate all use of it
* Make even more stuff inherit from ve.Element (long live this.$$)
* Use the correct document or window anywhere it was being assumed to be
the top level one
* Resolve stacking order issues by removing the excessive use of z-index
and introducing global and local overlay elements for each editor
* Add a surface to the reference dialog, load up the reference contents
and save them back on apply
* Actually destroy what we create in ce and ui surfaces
* Add recursive frame offset calculation method to ve.Element
* Moved ve.ce.Surface's getSelectionRect method to the prototype
Bonus:
* Move ve.ce.DocumentNode.css contents to ve.ce.Node.css (not sure why it
was separate in the first place, but I'm likely the one to blame)
* Fix blatant lies in documentation
* Whitespace cleanup here and there
* Get rid of ve.ui.Window overlays - not used or needed
Change-Id: Iede83e7d24f7cb249b6ba3dc45d770445b862e08
2013-05-20 22:45:50 +00:00
|
|
|
if ( !rangy.getSelection( this.$document[0] ).isCollapsed ) {
|
2013-09-30 13:26:33 +00:00
|
|
|
tx = ve.dm.Transaction.newFromRemoval( doc, selection );
|
2013-05-18 15:41:58 +00:00
|
|
|
selection = tx.translateRange( selection );
|
2013-09-07 09:32:05 +00:00
|
|
|
this.model.change( tx, selection );
|
2013-09-30 13:26:33 +00:00
|
|
|
selection = this.model.getSelection();
|
2012-06-20 01:20:28 +00:00
|
|
|
}
|
2012-06-27 16:29:58 +00:00
|
|
|
|
2013-09-07 09:32:05 +00:00
|
|
|
// Save scroll position before changing focus to "offscreen" paste target
|
|
|
|
this.beforePasteData.scrollTop = $window.scrollTop();
|
2013-09-30 13:26:33 +00:00
|
|
|
|
2013-09-07 09:32:05 +00:00
|
|
|
this.$pasteTarget.empty();
|
2013-09-30 13:26:33 +00:00
|
|
|
|
|
|
|
// Get node from cursor position
|
|
|
|
node = doc.getNodeFromOffset( selection.start );
|
|
|
|
if ( node.canContainContent() ) {
|
|
|
|
// If this is a content branch node, then add its DM HTML
|
|
|
|
// to the paste target to give CE some context.
|
|
|
|
textStart = textEnd = 0;
|
|
|
|
range = node.getRange();
|
|
|
|
context = [ node.getClonedElement() ];
|
|
|
|
// If there is content to the left of the cursor, put a placeholder
|
|
|
|
// character to the left of the cursor
|
|
|
|
if ( selection.start > range.start ) {
|
2013-11-07 14:30:41 +00:00
|
|
|
leftText = '☀';
|
2013-09-30 13:26:33 +00:00
|
|
|
context.push( leftText );
|
|
|
|
textStart = textEnd = 1;
|
|
|
|
}
|
|
|
|
// If there is content to the right of the cursor, put a placeholder
|
|
|
|
// character to the right of the cursor
|
|
|
|
if ( selection.end < range.end ) {
|
2013-11-07 14:30:41 +00:00
|
|
|
rightText = '☂';
|
2013-09-30 13:26:33 +00:00
|
|
|
context.push( rightText );
|
|
|
|
}
|
|
|
|
// If there is no text context, select some text to be replaced
|
|
|
|
if ( !leftText && !rightText ) {
|
2013-11-07 14:30:41 +00:00
|
|
|
context.push( '☁' );
|
2013-09-30 13:26:33 +00:00
|
|
|
textEnd = 1;
|
|
|
|
}
|
|
|
|
context.push( { 'type': '/' + context[0].type } );
|
|
|
|
|
|
|
|
ve.dm.converter.store = doc.getStore();
|
|
|
|
ve.dm.converter.internalList = doc.getInternalList();
|
|
|
|
ve.dm.converter.getDomSubtreeFromData( context, this.$pasteTarget[0] );
|
|
|
|
|
2013-12-10 19:15:04 +00:00
|
|
|
// Giving the paste target focus too late can cause problems in FF (!?)
|
|
|
|
// so do it up here.
|
|
|
|
this.$pasteTarget[0].focus();
|
|
|
|
|
2013-09-30 13:26:33 +00:00
|
|
|
rangyRange = rangy.createRange( this.getElementDocument() );
|
|
|
|
// Assume that the DM node only generated one child
|
|
|
|
textNode = this.$pasteTarget.children().contents()[0];
|
|
|
|
// Place the cursor between the placeholder characters
|
|
|
|
rangyRange.setStart( textNode, textStart );
|
|
|
|
rangyRange.setEnd( textNode, textEnd );
|
|
|
|
sel = rangy.getSelection( this.getElementDocument() );
|
|
|
|
sel.removeAllRanges();
|
|
|
|
sel.addRange( rangyRange, false );
|
|
|
|
|
|
|
|
this.beforePasteData.context = context;
|
|
|
|
this.beforePasteData.leftText = leftText;
|
|
|
|
this.beforePasteData.rightText = rightText;
|
|
|
|
} else {
|
|
|
|
// If we're not in a content branch node, don't bother trying to do
|
|
|
|
// anything clever with paste context
|
|
|
|
this.$pasteTarget[0].focus();
|
|
|
|
}
|
|
|
|
|
2013-09-07 09:32:05 +00:00
|
|
|
};
|
2012-04-06 15:10:30 +00:00
|
|
|
|
2013-09-07 09:32:05 +00:00
|
|
|
/**
|
|
|
|
* Handle post-paste events.
|
|
|
|
*
|
|
|
|
* @param {jQuery.Event} e Paste event
|
|
|
|
*/
|
|
|
|
ve.ce.Surface.prototype.afterPaste = function () {
|
|
|
|
var clipboardKey, clipboardId, clipboardIndex,
|
2013-09-30 13:26:33 +00:00
|
|
|
$elements, parts, pasteData, slice, tx, internalListRange,
|
2013-12-10 20:11:35 +00:00
|
|
|
data, doc, htmlDoc,
|
2013-09-30 13:26:33 +00:00
|
|
|
context, left, right, contextRange,
|
2013-09-07 09:32:05 +00:00
|
|
|
beforePasteData = this.beforePasteData || {},
|
2013-11-01 19:45:59 +00:00
|
|
|
$window = this.$( OO.ui.Element.getWindow( this.$.context ) ),
|
2013-09-07 09:32:05 +00:00
|
|
|
selection = this.model.getSelection();
|
2012-06-20 01:20:28 +00:00
|
|
|
|
2013-12-10 15:49:44 +00:00
|
|
|
// If the selection doesn't collapse after paste then nothing was inserted
|
|
|
|
if ( !rangy.getSelection( this.getElementDocument() ).isCollapsed ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-09-30 13:26:33 +00:00
|
|
|
// Remove the pasteProtect class. See #onCopy.
|
|
|
|
this.$pasteTarget.find( 'span' ).removeClass( 've-pasteProtect' );
|
|
|
|
|
|
|
|
// Find the clipboard key
|
2013-09-07 09:32:05 +00:00
|
|
|
if ( beforePasteData.custom ) {
|
|
|
|
clipboardKey = beforePasteData.custom;
|
|
|
|
} else {
|
2013-11-01 19:45:59 +00:00
|
|
|
$elements = beforePasteData.html ? this.$( $.parseHTML( beforePasteData.html ) ) : this.$pasteTarget.contents();
|
2013-06-27 21:56:16 +00:00
|
|
|
|
2013-09-07 09:32:05 +00:00
|
|
|
// Try to find the clipboard key hidden in the HTML
|
2013-09-30 13:26:33 +00:00
|
|
|
$elements = $elements.filter( function () {
|
2013-09-07 09:32:05 +00:00
|
|
|
var val = this.getAttribute && this.getAttribute( 'data-ve-clipboard-key' );
|
|
|
|
if ( val ) {
|
|
|
|
clipboardKey = val;
|
2013-09-30 13:26:33 +00:00
|
|
|
// Remove the clipboard key span once read
|
2013-09-07 09:32:05 +00:00
|
|
|
return false;
|
|
|
|
}
|
2013-09-30 13:26:33 +00:00
|
|
|
return true;
|
2013-09-07 09:32:05 +00:00
|
|
|
} );
|
|
|
|
}
|
2013-09-30 13:26:33 +00:00
|
|
|
|
|
|
|
// If we have a clipboard key, validate it and fetch data
|
2013-09-07 09:32:05 +00:00
|
|
|
if ( clipboardKey ) {
|
|
|
|
parts = clipboardKey.split( '-' );
|
|
|
|
clipboardId = parts[0];
|
|
|
|
clipboardIndex = parts[1];
|
|
|
|
if ( clipboardId === this.clipboardId && this.clipboard[clipboardIndex] ) {
|
2013-09-20 14:32:45 +00:00
|
|
|
// Hash validation: either text/xcustom was used or the hash must be
|
|
|
|
// equal to the hash of the pasted HTML to assert that the HTML
|
2013-09-07 09:32:05 +00:00
|
|
|
// hasn't been modified in another editor before being pasted back.
|
2013-09-20 14:32:45 +00:00
|
|
|
if ( beforePasteData.custom ||
|
2013-09-07 09:32:05 +00:00
|
|
|
this.clipboard[clipboardIndex].hash ===
|
2013-09-20 14:32:45 +00:00
|
|
|
this.constructor.static.getClipboardHash( $elements )
|
2013-09-07 09:32:05 +00:00
|
|
|
) {
|
2013-09-30 13:26:33 +00:00
|
|
|
slice = this.clipboard[clipboardIndex].slice;
|
2013-09-07 09:32:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-08-26 18:40:39 +00:00
|
|
|
|
2013-09-30 13:26:33 +00:00
|
|
|
if ( slice ) {
|
|
|
|
// Internal paste
|
|
|
|
try {
|
|
|
|
// Try to paste in the orignal data
|
|
|
|
// Take a copy to prevent the data being annotated a second time in the catch block
|
|
|
|
// and to prevent actions in the data model affecting view.clipboard
|
|
|
|
pasteData = new ve.dm.ElementLinearData(
|
|
|
|
slice.getStore(),
|
|
|
|
ve.copy( slice.getOriginalData() )
|
|
|
|
);
|
2012-12-07 22:58:29 +00:00
|
|
|
|
2013-10-07 20:45:19 +00:00
|
|
|
if ( this.pasteSpecial ) {
|
|
|
|
pasteData.sanitize( this.getSurface().getPasteRules(), true );
|
|
|
|
}
|
2013-09-07 09:32:05 +00:00
|
|
|
|
2013-09-30 13:26:33 +00:00
|
|
|
// Annotate
|
|
|
|
ve.dm.Document.static.addAnnotationsToData( pasteData.getData(), this.model.getInsertionAnnotations() );
|
2013-09-07 09:32:05 +00:00
|
|
|
|
2013-09-30 13:26:33 +00:00
|
|
|
// Transaction
|
|
|
|
tx = ve.dm.Transaction.newFromInsertion(
|
|
|
|
this.documentView.model,
|
|
|
|
selection.start,
|
|
|
|
pasteData.getData()
|
|
|
|
);
|
|
|
|
} catch ( err ) {
|
|
|
|
// If that fails, use the balanced data
|
|
|
|
// Take a copy to prevent actions in the data model affecting view.clipboard
|
|
|
|
pasteData = new ve.dm.ElementLinearData(
|
|
|
|
slice.getStore(),
|
|
|
|
ve.copy( slice.getBalancedData() )
|
|
|
|
);
|
2013-09-07 09:32:05 +00:00
|
|
|
|
2013-10-07 20:45:19 +00:00
|
|
|
if ( this.pasteSpecial ) {
|
|
|
|
pasteData.sanitize( this.getSurface().getPasteRules(), true );
|
|
|
|
}
|
|
|
|
|
2013-09-30 13:26:33 +00:00
|
|
|
// Annotate
|
|
|
|
ve.dm.Document.static.addAnnotationsToData( pasteData.getData(), this.model.getInsertionAnnotations() );
|
2013-09-07 09:32:05 +00:00
|
|
|
|
2013-09-30 13:26:33 +00:00
|
|
|
// Transaction
|
|
|
|
tx = ve.dm.Transaction.newFromInsertion(
|
|
|
|
this.documentView.model,
|
|
|
|
selection.start,
|
|
|
|
pasteData.getData()
|
|
|
|
);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if ( clipboardKey && beforePasteData.html ) {
|
|
|
|
// If the clipboardKey is set (paste from other VE instance), and clipboard
|
|
|
|
// data is available, then make sure important spans haven't been dropped
|
|
|
|
if ( !$elements ) {
|
|
|
|
$elements = this.$( $.parseHTML( beforePasteData.html ) );
|
|
|
|
}
|
|
|
|
if (
|
|
|
|
$elements.filter( 'span[id],span[typeof],span[rel]' ).length > 0 &&
|
|
|
|
this.$pasteTarget.filter('span[id],span[typeof],span[rel]').length === 0
|
|
|
|
) {
|
|
|
|
// CE destroyed an important span, so revert to using clipboard data
|
2013-12-10 20:11:35 +00:00
|
|
|
htmlDoc = ve.createDocumentFromHtml( beforePasteData.html );
|
|
|
|
// Remove the pasteProtect class. See #onCopy.
|
|
|
|
$( htmlDoc ).find( 'span' ).removeClass( 've-pasteProtect' );
|
2013-09-30 13:26:33 +00:00
|
|
|
beforePasteData.context = null;
|
|
|
|
}
|
|
|
|
}
|
2013-12-10 20:11:35 +00:00
|
|
|
if ( !htmlDoc ) {
|
2013-09-30 13:26:33 +00:00
|
|
|
// If there were no problems, let CE do its sanitizing as it may
|
|
|
|
// contain all sorts of horrible metadata (head tags etc.)
|
|
|
|
// TODO: IE will always take this path, and so may have bugs with span unwapping
|
|
|
|
// in edge cases (e.g. pasting a single MWReference)
|
2013-12-10 20:11:35 +00:00
|
|
|
htmlDoc = ve.createDocumentFromHtml( this.$pasteTarget.html() );
|
2013-09-30 13:26:33 +00:00
|
|
|
}
|
|
|
|
// External paste
|
2013-12-10 20:11:35 +00:00
|
|
|
doc = ve.dm.converter.getModelFromDom( htmlDoc );
|
2013-12-04 23:09:17 +00:00
|
|
|
data = doc.data;
|
|
|
|
// Clear metadata
|
|
|
|
doc.metadata = new ve.dm.MetaLinearData( doc.getStore(), new Array( 1 + data.getLength() ) );
|
2013-10-07 20:45:19 +00:00
|
|
|
// If the clipboardKey is set (paste from other VE instance), and it's a non-special paste, skip sanitization
|
|
|
|
if ( !clipboardKey || this.pasteSpecial ) {
|
|
|
|
data.sanitize( this.getSurface().getPasteRules(), this.pasteSpecial );
|
2013-09-30 13:26:33 +00:00
|
|
|
} else {
|
|
|
|
// ...except not quite - contentEditable can't be trusted not
|
|
|
|
// to add styles, so for now remove them
|
|
|
|
// TODO: store original styles in data
|
2013-12-09 19:46:53 +00:00
|
|
|
data.sanitize( { 'removeStyles': true } );
|
2013-09-30 13:26:33 +00:00
|
|
|
}
|
|
|
|
data.remapInternalListKeys( this.model.getDocument().getInternalList() );
|
|
|
|
|
2013-12-04 23:09:17 +00:00
|
|
|
// Initialize node tree
|
|
|
|
doc.buildNodeTree();
|
|
|
|
|
2013-09-30 13:26:33 +00:00
|
|
|
// If the paste was given context, calculate the range of the inserted data
|
|
|
|
if ( beforePasteData.context ) {
|
|
|
|
internalListRange = doc.getInternalList().getListNode().getOuterRange();
|
|
|
|
context = new ve.dm.ElementLinearData(
|
2013-12-04 17:37:50 +00:00
|
|
|
doc.getStore(),
|
2013-09-30 13:26:33 +00:00
|
|
|
ve.copy( beforePasteData.context )
|
|
|
|
);
|
2013-10-07 20:45:19 +00:00
|
|
|
if ( this.pasteSpecial ) {
|
|
|
|
// The context may have been sanitized, so sanitize here as well for comparison
|
|
|
|
context.sanitize( this.getSurface().getPasteRules(), this.pasteSpecial, true );
|
|
|
|
}
|
2013-09-30 13:26:33 +00:00
|
|
|
|
|
|
|
// Remove matching context from the left
|
|
|
|
left = 0;
|
|
|
|
while (
|
|
|
|
context.getLength() &&
|
|
|
|
ve.dm.ElementLinearData.static.compareUnannotated(
|
|
|
|
data.getData( left ),
|
|
|
|
data.isElementData( left ) ? context.getData( 0 ) : beforePasteData.leftText
|
|
|
|
)
|
|
|
|
) {
|
|
|
|
left++;
|
|
|
|
context.splice( 0, 1 );
|
|
|
|
}
|
2013-09-07 09:32:05 +00:00
|
|
|
|
2013-09-30 13:26:33 +00:00
|
|
|
// Remove matching context from the right
|
|
|
|
right = internalListRange.start;
|
|
|
|
while (
|
|
|
|
context.getLength() &&
|
|
|
|
ve.dm.ElementLinearData.static.compareUnannotated(
|
|
|
|
data.getData( right - 1 ),
|
|
|
|
data.isElementData( right - 1 ) ? context.getData( context.getLength() - 1 ) : beforePasteData.rightText
|
|
|
|
)
|
|
|
|
) {
|
|
|
|
right--;
|
|
|
|
context.splice( context.getLength() - 1, 1 );
|
|
|
|
}
|
|
|
|
contextRange = new ve.Range( left, right );
|
|
|
|
}
|
2013-09-07 09:32:05 +00:00
|
|
|
|
2013-09-30 13:26:33 +00:00
|
|
|
tx = ve.dm.Transaction.newFromDocumentInsertion(
|
2013-09-07 09:32:05 +00:00
|
|
|
this.documentView.model,
|
|
|
|
selection.start,
|
2013-09-30 13:26:33 +00:00
|
|
|
doc,
|
|
|
|
contextRange
|
2013-09-07 09:32:05 +00:00
|
|
|
);
|
|
|
|
}
|
2012-12-07 22:58:29 +00:00
|
|
|
|
2013-09-07 09:32:05 +00:00
|
|
|
// Restore focus and scroll position
|
2013-12-04 19:42:44 +00:00
|
|
|
this.documentView.getDocumentNode().$element[0].focus();
|
2013-09-07 09:32:05 +00:00
|
|
|
$window.scrollTop( beforePasteData.scrollTop );
|
2012-12-07 22:58:29 +00:00
|
|
|
|
2013-09-07 09:32:05 +00:00
|
|
|
selection = tx.translateRange( selection );
|
|
|
|
this.model.change( tx, new ve.Range( selection.start ) );
|
|
|
|
// Move cursor to end of selection
|
2013-10-15 18:36:02 +00:00
|
|
|
this.model.setSelection( new ve.Range( selection.end ) );
|
2012-06-20 01:20:28 +00:00
|
|
|
};
|
|
|
|
|
Make use of new jshint options
* Restricting "camelcase":
No changes, we were passing all of these already
* Explicitly unrestricting "forin" and "plusplus"
These are off by default in node-jshint, but some distro of jshint
and editors that use their own wrapper around jshint instead of
node-jshint (Eclipse?) may have different defaults. Therefor
setting them to false explicitly. This also serves as a reminder
for the future so we'll always know we don't pass that, in case
we would want to change that.
* Fix order ("quotemark" before "regexp")
* Restricting "unused"
We're not passing all of this, which is why I've set it to false
for now. But I did put it in .jshintrc as placeholder.
I've fixed most of them, there's some left where there is no clean
solution.
* While at it fix a few issues:
- Unused variables ($target, $window)
- Bad practices (using jQuery context for find instead of creation)
- Redundant /*global */ comments
- Parameters that are not used and don't have documentation either
- Lines longer than 100 chars @ 4 spaces/tab
* Note:
- ve.ce.Surface.prototype.onChange takes two arguments but never
uses the former. And even the second one can be null/undefined.
Aside from that, the .change() function emits
another event for the transaction already. Looks like this
should be refactored a bit, two more separated events probably
or one that is actually used better.
- Also cleaned up a lot of comments, some of which were missing,
others were incorrect
- Reworked the contentChange event so we are no longer using the
word new as an object key; expanded a complex object into multiple
arguments being passed through the event to make it easier to work
with and document
Change-Id: I8490815a508c6c379d5f9a743bb4aefd14576aa6
2012-08-07 06:02:18 +00:00
|
|
|
/**
|
2013-01-16 21:51:05 +00:00
|
|
|
* Handle document composition start events.
|
Make use of new jshint options
* Restricting "camelcase":
No changes, we were passing all of these already
* Explicitly unrestricting "forin" and "plusplus"
These are off by default in node-jshint, but some distro of jshint
and editors that use their own wrapper around jshint instead of
node-jshint (Eclipse?) may have different defaults. Therefor
setting them to false explicitly. This also serves as a reminder
for the future so we'll always know we don't pass that, in case
we would want to change that.
* Fix order ("quotemark" before "regexp")
* Restricting "unused"
We're not passing all of this, which is why I've set it to false
for now. But I did put it in .jshintrc as placeholder.
I've fixed most of them, there's some left where there is no clean
solution.
* While at it fix a few issues:
- Unused variables ($target, $window)
- Bad practices (using jQuery context for find instead of creation)
- Redundant /*global */ comments
- Parameters that are not used and don't have documentation either
- Lines longer than 100 chars @ 4 spaces/tab
* Note:
- ve.ce.Surface.prototype.onChange takes two arguments but never
uses the former. And even the second one can be null/undefined.
Aside from that, the .change() function emits
another event for the transaction already. Looks like this
should be refactored a bit, two more separated events probably
or one that is actually used better.
- Also cleaned up a lot of comments, some of which were missing,
others were incorrect
- Reworked the contentChange event so we are no longer using the
word new as an object key; expanded a complex object into multiple
arguments being passed through the event to make it easier to work
with and document
Change-Id: I8490815a508c6c379d5f9a743bb4aefd14576aa6
2012-08-07 06:02:18 +00:00
|
|
|
*
|
|
|
|
* @method
|
Major UI refactoring and improvements
Objective:
Refactor UI widgets, improve usability and accessibility of menus, general cleanup and style improvements.
Extras:
Fixed documentation in a few other files to make descriptions of jQuery event arguments more consistent, classes inherit correctly, and made use of the @cfg functionality in jsduck.
Changes:
.docs/config.json
* Added window, HTMLDocument, HTMLElement, DocumentFragment and XMLHttpRequest to externals, so jsduck doesn't throw warnings when they are used
demos/ve/index.php, modules/ve/test/index.php, VisualEditor.php
* Moved widgets above tools (since tools use widgets)
demos/ve/index.php
* Refactored widget initialization to use options
* Renamed variables to match widget names
ve.init.mw.ViewPageTarget.css
* Adjusted text sizes to make widgets work normally
* Added margins for buttons in toolbar (since button widgets
don't have any)
* Removed styles for init buttons (button widgets now)
ve.init.mw.ViewPageTarget.js
* Switched to using button widgets (involved moving things around
a bit)
ve.ui.LinkInspector.js, ve.ui.MWLinkInspector.js
* Renamed static property "inputWidget" to
"linkTargetInputWidget" to better reflect the required base class
for the properties value
icons.ai, check.png, check.svg
* Added "check" icon, used in menu right now to show which item
is selected
ve.ui.Icons-raster.css, ve.ui.Icons-vector.css
* Added check icon
* Removed :before pseudo selectors from most of the icon classes (not need by button tool anymore, makes them more reusable now)
ve.ui.Tool.css
* Adjusted drop down tool styles so menu appears below, instead
of on top, of the label
* Adjusted paragraph font size to better match actual content
* Updated class names to still work with menu widget changes
(items are their own widgets now)
* Updated selectors as per changes in the structure of button tools
ve.ui.Widget.css
* Added styles for buttons and menu items
* Adjusted menu styles
ve.ui.*ButtonTool.js
* Added config options argument passthrough
ve.ui.ButtonTool.js
* Moved var statement to the top inside constructor
* Switched to using "a" tag to get cross-browser :active support
* Added icon to inside of button to make icon styles more reusable
* Removed disabled support (now provided by widget parent class)
ve.ui.FormatDropDownTool.js
* Updated options initialization to construct menu item objects
* Modified handling of items to account for changes in menu and
item classes
* Optimized onUpdateState method a bit, adding early exit to
inner loop
ve.ui.ButtonTool.js, ve.ui.DropdownTool.js, ve.ui.Context.js,
ve.ui.Frame, ve.ui.Tool.js, ve.ui.Widget.js
* Added chain ability to non-getter methods
ve.ui.DropdownTool.js
* Removed items argument to constructor
* Updated code as per changes in menu class
* Fixed inconsistent naming of event handler methods
* Removed item event handling (now handled by items directly)
* Made use of this.$$ to ensure tool works in other frames
ve.ui.Tool.js
* Made tools inherit from widget
* Moved trigger registry event handler to a method
ve.ui.Context.js
* Switched from using menu to contain toolbar to a simple wrapper
ve.ui.js
* Added get$$ method, a convenience function for binding jQuery
to a specific document context
ve.ui.*Widget.js
* Switched to using a config options object instead of individual arguments
* Added options
* Factored out flags and labels into their own classes
* Refactored value setting methods for inputs
ve.ui.MenuWidget.js, ve.ui.MenuItemWidget.js
* Broke items out into their own classes
* Redesigned API
* Updated code that uses these classes
* Added support for keyboard interaction
* Made items flash when selected (delaying the hiding of the menu for 200ms)
ve.ui.LinkTargetInputWidget.js, ve.ui.MWLinkTargetInputWidget
* Refactored annotation setting methods
Change-Id: I7769bd5a5b79f1ab36f258ef9f2be583ca503ce6
2013-02-20 23:25:12 +00:00
|
|
|
* @param {jQuery.Event} e Composition start event
|
Make use of new jshint options
* Restricting "camelcase":
No changes, we were passing all of these already
* Explicitly unrestricting "forin" and "plusplus"
These are off by default in node-jshint, but some distro of jshint
and editors that use their own wrapper around jshint instead of
node-jshint (Eclipse?) may have different defaults. Therefor
setting them to false explicitly. This also serves as a reminder
for the future so we'll always know we don't pass that, in case
we would want to change that.
* Fix order ("quotemark" before "regexp")
* Restricting "unused"
We're not passing all of this, which is why I've set it to false
for now. But I did put it in .jshintrc as placeholder.
I've fixed most of them, there's some left where there is no clean
solution.
* While at it fix a few issues:
- Unused variables ($target, $window)
- Bad practices (using jQuery context for find instead of creation)
- Redundant /*global */ comments
- Parameters that are not used and don't have documentation either
- Lines longer than 100 chars @ 4 spaces/tab
* Note:
- ve.ce.Surface.prototype.onChange takes two arguments but never
uses the former. And even the second one can be null/undefined.
Aside from that, the .change() function emits
another event for the transaction already. Looks like this
should be refactored a bit, two more separated events probably
or one that is actually used better.
- Also cleaned up a lot of comments, some of which were missing,
others were incorrect
- Reworked the contentChange event so we are no longer using the
word new as an object key; expanded a complex object into multiple
arguments being passed through the event to make it easier to work
with and document
Change-Id: I8490815a508c6c379d5f9a743bb4aefd14576aa6
2012-08-07 06:02:18 +00:00
|
|
|
*/
|
2013-01-16 21:51:05 +00:00
|
|
|
ve.ce.Surface.prototype.onDocumentCompositionStart = function () {
|
|
|
|
if ( $.browser.msie === true ) {
|
2012-06-21 06:21:53 +00:00
|
|
|
return;
|
|
|
|
}
|
2013-01-16 21:51:05 +00:00
|
|
|
this.inIme = true;
|
2012-10-11 18:31:28 +00:00
|
|
|
this.handleInsertion();
|
2012-04-06 15:10:30 +00:00
|
|
|
};
|
|
|
|
|
2013-01-16 21:51:05 +00:00
|
|
|
/**
|
|
|
|
* Handle document composition end events.
|
|
|
|
*
|
|
|
|
* @method
|
Major UI refactoring and improvements
Objective:
Refactor UI widgets, improve usability and accessibility of menus, general cleanup and style improvements.
Extras:
Fixed documentation in a few other files to make descriptions of jQuery event arguments more consistent, classes inherit correctly, and made use of the @cfg functionality in jsduck.
Changes:
.docs/config.json
* Added window, HTMLDocument, HTMLElement, DocumentFragment and XMLHttpRequest to externals, so jsduck doesn't throw warnings when they are used
demos/ve/index.php, modules/ve/test/index.php, VisualEditor.php
* Moved widgets above tools (since tools use widgets)
demos/ve/index.php
* Refactored widget initialization to use options
* Renamed variables to match widget names
ve.init.mw.ViewPageTarget.css
* Adjusted text sizes to make widgets work normally
* Added margins for buttons in toolbar (since button widgets
don't have any)
* Removed styles for init buttons (button widgets now)
ve.init.mw.ViewPageTarget.js
* Switched to using button widgets (involved moving things around
a bit)
ve.ui.LinkInspector.js, ve.ui.MWLinkInspector.js
* Renamed static property "inputWidget" to
"linkTargetInputWidget" to better reflect the required base class
for the properties value
icons.ai, check.png, check.svg
* Added "check" icon, used in menu right now to show which item
is selected
ve.ui.Icons-raster.css, ve.ui.Icons-vector.css
* Added check icon
* Removed :before pseudo selectors from most of the icon classes (not need by button tool anymore, makes them more reusable now)
ve.ui.Tool.css
* Adjusted drop down tool styles so menu appears below, instead
of on top, of the label
* Adjusted paragraph font size to better match actual content
* Updated class names to still work with menu widget changes
(items are their own widgets now)
* Updated selectors as per changes in the structure of button tools
ve.ui.Widget.css
* Added styles for buttons and menu items
* Adjusted menu styles
ve.ui.*ButtonTool.js
* Added config options argument passthrough
ve.ui.ButtonTool.js
* Moved var statement to the top inside constructor
* Switched to using "a" tag to get cross-browser :active support
* Added icon to inside of button to make icon styles more reusable
* Removed disabled support (now provided by widget parent class)
ve.ui.FormatDropDownTool.js
* Updated options initialization to construct menu item objects
* Modified handling of items to account for changes in menu and
item classes
* Optimized onUpdateState method a bit, adding early exit to
inner loop
ve.ui.ButtonTool.js, ve.ui.DropdownTool.js, ve.ui.Context.js,
ve.ui.Frame, ve.ui.Tool.js, ve.ui.Widget.js
* Added chain ability to non-getter methods
ve.ui.DropdownTool.js
* Removed items argument to constructor
* Updated code as per changes in menu class
* Fixed inconsistent naming of event handler methods
* Removed item event handling (now handled by items directly)
* Made use of this.$$ to ensure tool works in other frames
ve.ui.Tool.js
* Made tools inherit from widget
* Moved trigger registry event handler to a method
ve.ui.Context.js
* Switched from using menu to contain toolbar to a simple wrapper
ve.ui.js
* Added get$$ method, a convenience function for binding jQuery
to a specific document context
ve.ui.*Widget.js
* Switched to using a config options object instead of individual arguments
* Added options
* Factored out flags and labels into their own classes
* Refactored value setting methods for inputs
ve.ui.MenuWidget.js, ve.ui.MenuItemWidget.js
* Broke items out into their own classes
* Redesigned API
* Updated code that uses these classes
* Added support for keyboard interaction
* Made items flash when selected (delaying the hiding of the menu for 200ms)
ve.ui.LinkTargetInputWidget.js, ve.ui.MWLinkTargetInputWidget
* Refactored annotation setting methods
Change-Id: I7769bd5a5b79f1ab36f258ef9f2be583ca503ce6
2013-02-20 23:25:12 +00:00
|
|
|
* @param {jQuery.Event} e Composition end event
|
2013-01-16 21:51:05 +00:00
|
|
|
*/
|
|
|
|
ve.ce.Surface.prototype.onDocumentCompositionEnd = function () {
|
|
|
|
this.inIme = false;
|
2013-09-07 01:03:10 +00:00
|
|
|
this.incRenderLock();
|
|
|
|
try {
|
|
|
|
this.surfaceObserver.pollOnce();
|
|
|
|
} finally {
|
|
|
|
this.decRenderLock();
|
|
|
|
}
|
|
|
|
this.surfaceObserver.startTimerLoop();
|
2013-01-16 21:51:05 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/*! Custom Events */
|
|
|
|
|
Make use of new jshint options
* Restricting "camelcase":
No changes, we were passing all of these already
* Explicitly unrestricting "forin" and "plusplus"
These are off by default in node-jshint, but some distro of jshint
and editors that use their own wrapper around jshint instead of
node-jshint (Eclipse?) may have different defaults. Therefor
setting them to false explicitly. This also serves as a reminder
for the future so we'll always know we don't pass that, in case
we would want to change that.
* Fix order ("quotemark" before "regexp")
* Restricting "unused"
We're not passing all of this, which is why I've set it to false
for now. But I did put it in .jshintrc as placeholder.
I've fixed most of them, there's some left where there is no clean
solution.
* While at it fix a few issues:
- Unused variables ($target, $window)
- Bad practices (using jQuery context for find instead of creation)
- Redundant /*global */ comments
- Parameters that are not used and don't have documentation either
- Lines longer than 100 chars @ 4 spaces/tab
* Note:
- ve.ce.Surface.prototype.onChange takes two arguments but never
uses the former. And even the second one can be null/undefined.
Aside from that, the .change() function emits
another event for the transaction already. Looks like this
should be refactored a bit, two more separated events probably
or one that is actually used better.
- Also cleaned up a lot of comments, some of which were missing,
others were incorrect
- Reworked the contentChange event so we are no longer using the
word new as an object key; expanded a complex object into multiple
arguments being passed through the event to make it easier to work
with and document
Change-Id: I8490815a508c6c379d5f9a743bb4aefd14576aa6
2012-08-07 06:02:18 +00:00
|
|
|
/**
|
2013-10-01 02:57:18 +00:00
|
|
|
* Handle model select events.
|
2013-01-15 23:38:49 +00:00
|
|
|
*
|
2013-03-20 07:09:43 +00:00
|
|
|
* @see ve.dm.Surface#method-change
|
Make use of new jshint options
* Restricting "camelcase":
No changes, we were passing all of these already
* Explicitly unrestricting "forin" and "plusplus"
These are off by default in node-jshint, but some distro of jshint
and editors that use their own wrapper around jshint instead of
node-jshint (Eclipse?) may have different defaults. Therefor
setting them to false explicitly. This also serves as a reminder
for the future so we'll always know we don't pass that, in case
we would want to change that.
* Fix order ("quotemark" before "regexp")
* Restricting "unused"
We're not passing all of this, which is why I've set it to false
for now. But I did put it in .jshintrc as placeholder.
I've fixed most of them, there's some left where there is no clean
solution.
* While at it fix a few issues:
- Unused variables ($target, $window)
- Bad practices (using jQuery context for find instead of creation)
- Redundant /*global */ comments
- Parameters that are not used and don't have documentation either
- Lines longer than 100 chars @ 4 spaces/tab
* Note:
- ve.ce.Surface.prototype.onChange takes two arguments but never
uses the former. And even the second one can be null/undefined.
Aside from that, the .change() function emits
another event for the transaction already. Looks like this
should be refactored a bit, two more separated events probably
or one that is actually used better.
- Also cleaned up a lot of comments, some of which were missing,
others were incorrect
- Reworked the contentChange event so we are no longer using the
word new as an object key; expanded a complex object into multiple
arguments being passed through the event to make it easier to work
with and document
Change-Id: I8490815a508c6c379d5f9a743bb4aefd14576aa6
2012-08-07 06:02:18 +00:00
|
|
|
*
|
|
|
|
* @method
|
2013-10-01 02:57:18 +00:00
|
|
|
* @param {ve.Range} selection
|
Make use of new jshint options
* Restricting "camelcase":
No changes, we were passing all of these already
* Explicitly unrestricting "forin" and "plusplus"
These are off by default in node-jshint, but some distro of jshint
and editors that use their own wrapper around jshint instead of
node-jshint (Eclipse?) may have different defaults. Therefor
setting them to false explicitly. This also serves as a reminder
for the future so we'll always know we don't pass that, in case
we would want to change that.
* Fix order ("quotemark" before "regexp")
* Restricting "unused"
We're not passing all of this, which is why I've set it to false
for now. But I did put it in .jshintrc as placeholder.
I've fixed most of them, there's some left where there is no clean
solution.
* While at it fix a few issues:
- Unused variables ($target, $window)
- Bad practices (using jQuery context for find instead of creation)
- Redundant /*global */ comments
- Parameters that are not used and don't have documentation either
- Lines longer than 100 chars @ 4 spaces/tab
* Note:
- ve.ce.Surface.prototype.onChange takes two arguments but never
uses the former. And even the second one can be null/undefined.
Aside from that, the .change() function emits
another event for the transaction already. Looks like this
should be refactored a bit, two more separated events probably
or one that is actually used better.
- Also cleaned up a lot of comments, some of which were missing,
others were incorrect
- Reworked the contentChange event so we are no longer using the
word new as an object key; expanded a complex object into multiple
arguments being passed through the event to make it easier to work
with and document
Change-Id: I8490815a508c6c379d5f9a743bb4aefd14576aa6
2012-08-07 06:02:18 +00:00
|
|
|
*/
|
2013-10-01 02:57:18 +00:00
|
|
|
ve.ce.Surface.prototype.onModelSelect = function ( selection ) {
|
2013-09-07 09:32:05 +00:00
|
|
|
var start, end, rangySel, rangyRange,
|
2013-04-18 20:54:37 +00:00
|
|
|
next = null,
|
|
|
|
previous = this.focusedNode;
|
|
|
|
|
2013-10-24 22:18:35 +00:00
|
|
|
this.contentBranchNodeChanged = false;
|
|
|
|
|
2013-10-01 02:57:18 +00:00
|
|
|
// Detect when only a single inline element is selected
|
|
|
|
if ( !selection.isCollapsed() ) {
|
|
|
|
start = this.documentView.getDocumentNode().getNodeFromOffset( selection.start + 1 );
|
|
|
|
if ( start.isFocusable() ) {
|
|
|
|
end = this.documentView.getDocumentNode().getNodeFromOffset( selection.end - 1 );
|
|
|
|
if ( start === end ) {
|
2013-09-24 15:53:55 +00:00
|
|
|
next = start;
|
|
|
|
}
|
2013-04-18 20:54:37 +00:00
|
|
|
}
|
2013-10-01 02:57:18 +00:00
|
|
|
} else {
|
|
|
|
// Check we haven't been programmatically placed inside a focusable node with a collapsed selection
|
|
|
|
start = this.documentView.getDocumentNode().getNodeFromOffset( selection.start );
|
|
|
|
if ( start.isFocusable() ) {
|
|
|
|
next = start;
|
2013-04-18 20:54:37 +00:00
|
|
|
}
|
2013-10-01 02:57:18 +00:00
|
|
|
}
|
2013-12-09 22:31:08 +00:00
|
|
|
// Update nodes
|
|
|
|
// Even update this if previous === next, because this function is called by the focus handler
|
|
|
|
// to restore a lost selection state
|
|
|
|
if ( previous ) {
|
|
|
|
previous.setFocused( false );
|
|
|
|
this.focusedNode = null;
|
|
|
|
if ( !next ) {
|
|
|
|
// If the selection is moving from a focusable node (in the paste target) back
|
|
|
|
// to a normal selection (in the document node), give the focus back to the
|
|
|
|
// document node.
|
|
|
|
this.documentView.getDocumentNode().$element[0].focus();
|
2013-06-05 20:59:19 +00:00
|
|
|
}
|
2012-03-07 19:37:17 +00:00
|
|
|
}
|
2013-12-09 22:31:08 +00:00
|
|
|
if ( next ) {
|
|
|
|
next.setFocused( true );
|
|
|
|
this.focusedNode = start;
|
|
|
|
// As FF won't fire a copy event with nothing selected, make
|
|
|
|
// a dummy selection of one space in the pasteTarget.
|
|
|
|
// onCopy will ignore this native selection and use the DM selection
|
|
|
|
this.$pasteTarget.text( ' ' );
|
|
|
|
rangySel = rangy.getSelection( this.getElementDocument() );
|
|
|
|
rangyRange = rangy.createRange( this.getElementDocument() );
|
|
|
|
rangyRange.setStart( this.$pasteTarget[0], 0 );
|
|
|
|
rangyRange.setEnd( this.$pasteTarget[0], 1 );
|
|
|
|
rangySel.removeAllRanges();
|
|
|
|
this.$pasteTarget[0].focus();
|
|
|
|
rangySel.addRange( rangyRange, false );
|
|
|
|
// Since the selection is no longer in the documentNode, clear the SurfaceObserver's
|
|
|
|
// selection state. Otherwise, if the user places the selection back into the documentNode
|
|
|
|
// in exactly the same place where it was before, the observer won't consider that a change.
|
|
|
|
this.surfaceObserver.clear();
|
|
|
|
}
|
2013-10-01 02:57:18 +00:00
|
|
|
|
|
|
|
// If there is no focused node, use native selection, but ignore the selection if
|
|
|
|
// changeModelSelection is currently being called with the same (object-identical)
|
|
|
|
// selection object (i.e. if the model is calling us back)
|
|
|
|
if ( !this.focusedNode && !this.isRenderingLocked() && selection !== this.newModelSelection ) {
|
|
|
|
this.showSelection( selection );
|
|
|
|
}
|
2013-10-01 23:40:08 +00:00
|
|
|
|
|
|
|
// Update the selection state in the SurfaceObserver
|
|
|
|
this.surfaceObserver.pollOnceNoEmit();
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Handle documentUpdate events on the surface model.
|
|
|
|
* @param {ve.dm.Transaction} transaction Transaction that was processed
|
|
|
|
*/
|
|
|
|
ve.ce.Surface.prototype.onModelDocumentUpdate = function () {
|
2013-10-24 22:18:35 +00:00
|
|
|
if ( this.contentBranchNodeChanged ) {
|
|
|
|
// Update the selection state from model
|
|
|
|
this.onModelSelect( this.surface.getModel().selection );
|
|
|
|
}
|
2013-10-01 23:40:08 +00:00
|
|
|
// Update the state of the SurfaceObserver
|
|
|
|
this.surfaceObserver.pollOnceNoEmit();
|
2012-03-07 19:37:17 +00:00
|
|
|
};
|
|
|
|
|
2013-01-16 21:51:05 +00:00
|
|
|
/**
|
|
|
|
* Handle selection change events.
|
|
|
|
*
|
2013-09-07 01:03:10 +00:00
|
|
|
* @see ve.ce.SurfaceObserver#pollOnce
|
2013-01-16 21:51:05 +00:00
|
|
|
*
|
|
|
|
* @method
|
|
|
|
* @param {ve.Range} oldRange
|
|
|
|
* @param {ve.Range} newRange
|
|
|
|
*/
|
|
|
|
ve.ce.Surface.prototype.onSelectionChange = function ( oldRange, newRange ) {
|
2013-03-22 18:44:32 +00:00
|
|
|
if ( oldRange && newRange.flip().equals( oldRange ) ) {
|
|
|
|
// Ignore when the newRange is just a flipped oldRange
|
|
|
|
return;
|
|
|
|
}
|
2013-09-04 22:24:08 +00:00
|
|
|
this.incRenderLock();
|
|
|
|
try {
|
2013-10-01 02:57:18 +00:00
|
|
|
this.changeModel( null, newRange );
|
2013-09-04 22:24:08 +00:00
|
|
|
} finally {
|
|
|
|
this.decRenderLock();
|
|
|
|
}
|
2013-01-16 21:51:05 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Handle content change events.
|
|
|
|
*
|
2013-09-07 01:03:10 +00:00
|
|
|
* @see ve.ce.SurfaceObserver#pollOnce
|
2013-01-16 21:51:05 +00:00
|
|
|
*
|
|
|
|
* @method
|
2013-09-27 10:30:29 +00:00
|
|
|
* @param {ve.ce.Node} node CE node the change occured in
|
2013-01-16 21:51:05 +00:00
|
|
|
* @param {Object} previous Old data
|
|
|
|
* @param {Object} previous.text Old plain text content
|
|
|
|
* @param {Object} previous.hash Old DOM hash
|
2013-03-20 07:09:43 +00:00
|
|
|
* @param {ve.Range} previous.range Old selection
|
2013-01-16 21:51:05 +00:00
|
|
|
* @param {Object} next New data
|
|
|
|
* @param {Object} next.text New plain text content
|
|
|
|
* @param {Object} next.hash New DOM hash
|
2013-03-20 07:09:43 +00:00
|
|
|
* @param {ve.Range} next.range New selection
|
2013-01-16 21:51:05 +00:00
|
|
|
*/
|
|
|
|
ve.ce.Surface.prototype.onContentChange = function ( node, previous, next ) {
|
|
|
|
var data, range, len, annotations, offsetDiff, lengthDiff, sameLeadingAndTrailing,
|
|
|
|
previousStart, nextStart, newRange,
|
2013-07-15 21:57:40 +00:00
|
|
|
previousData, nextData,
|
2013-09-27 10:30:29 +00:00
|
|
|
i, length, annotation, annotationIndex, dataString,
|
2013-07-17 15:49:16 +00:00
|
|
|
annotationsLeft, annotationsRight,
|
2013-01-16 21:51:05 +00:00
|
|
|
fromLeft = 0,
|
|
|
|
fromRight = 0,
|
|
|
|
nodeOffset = node.getModel().getOffset();
|
|
|
|
|
|
|
|
if ( previous.range && next.range ) {
|
|
|
|
offsetDiff = ( previous.range.isCollapsed() && next.range.isCollapsed() ) ?
|
|
|
|
next.range.start - previous.range.start : null;
|
|
|
|
lengthDiff = next.text.length - previous.text.length;
|
|
|
|
previousStart = previous.range.start - nodeOffset - 1;
|
|
|
|
nextStart = next.range.start - nodeOffset - 1;
|
|
|
|
sameLeadingAndTrailing = offsetDiff !== null && (
|
|
|
|
// TODO: rewrite to static method with tests
|
|
|
|
(
|
|
|
|
lengthDiff > 0 &&
|
|
|
|
previous.text.substring( 0, previousStart ) ===
|
2013-05-06 11:34:32 +00:00
|
|
|
next.text.substring( 0, previousStart ) &&
|
2013-01-16 21:51:05 +00:00
|
|
|
previous.text.substring( previousStart ) ===
|
2013-05-06 11:34:32 +00:00
|
|
|
next.text.substring( nextStart )
|
2013-01-16 21:51:05 +00:00
|
|
|
) ||
|
|
|
|
(
|
|
|
|
lengthDiff < 0 &&
|
|
|
|
previous.text.substring( 0, nextStart ) ===
|
|
|
|
next.text.substring( 0, nextStart ) &&
|
2013-06-24 17:51:59 +00:00
|
|
|
previous.text.substring( previousStart - lengthDiff + offsetDiff ) ===
|
2013-01-16 21:51:05 +00:00
|
|
|
next.text.substring( nextStart )
|
|
|
|
)
|
|
|
|
);
|
|
|
|
|
|
|
|
// Simple insertion
|
|
|
|
if ( lengthDiff > 0 && offsetDiff === lengthDiff /* && sameLeadingAndTrailing */) {
|
2013-06-20 23:28:56 +00:00
|
|
|
data = ve.splitClusters( next.text ).slice(
|
2013-01-16 21:51:05 +00:00
|
|
|
previous.range.start - nodeOffset - 1,
|
|
|
|
next.range.start - nodeOffset - 1
|
2013-06-20 23:28:56 +00:00
|
|
|
);
|
2013-01-16 21:51:05 +00:00
|
|
|
// Apply insertion annotations
|
|
|
|
annotations = this.model.getInsertionAnnotations();
|
2013-03-20 22:35:05 +00:00
|
|
|
if ( annotations instanceof ve.dm.AnnotationSet ) {
|
2013-10-04 14:27:00 +00:00
|
|
|
ve.dm.Document.static.addAnnotationsToData( data, this.model.getInsertionAnnotations() );
|
2013-01-16 21:51:05 +00:00
|
|
|
}
|
2013-09-04 22:24:08 +00:00
|
|
|
this.incRenderLock();
|
|
|
|
try {
|
2013-10-01 02:57:18 +00:00
|
|
|
this.changeModel(
|
2013-09-04 22:24:08 +00:00
|
|
|
ve.dm.Transaction.newFromInsertion(
|
|
|
|
this.documentView.model, previous.range.start, data
|
|
|
|
),
|
|
|
|
next.range
|
|
|
|
);
|
|
|
|
} finally {
|
|
|
|
this.decRenderLock();
|
|
|
|
}
|
2013-01-16 21:51:05 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Simple deletion
|
|
|
|
if ( ( offsetDiff === 0 || offsetDiff === lengthDiff ) && sameLeadingAndTrailing ) {
|
|
|
|
if ( offsetDiff === 0 ) {
|
|
|
|
range = new ve.Range( next.range.start, next.range.start - lengthDiff );
|
|
|
|
} else {
|
|
|
|
range = new ve.Range( next.range.start, previous.range.start );
|
|
|
|
}
|
2013-09-04 22:24:08 +00:00
|
|
|
this.incRenderLock();
|
|
|
|
try {
|
2013-10-01 02:57:18 +00:00
|
|
|
this.changeModel(
|
2013-09-04 22:24:08 +00:00
|
|
|
ve.dm.Transaction.newFromRemoval( this.documentView.model,
|
|
|
|
range ),
|
|
|
|
next.range
|
|
|
|
);
|
|
|
|
} finally {
|
|
|
|
this.decRenderLock();
|
|
|
|
}
|
2013-01-16 21:51:05 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Complex change
|
|
|
|
|
2013-07-15 21:57:40 +00:00
|
|
|
previousData = ve.splitClusters( previous.text );
|
|
|
|
nextData = ve.splitClusters( next.text );
|
|
|
|
len = Math.min( previousData.length, nextData.length );
|
2013-01-16 21:51:05 +00:00
|
|
|
// Count same characters from left
|
2013-07-15 21:57:40 +00:00
|
|
|
while ( fromLeft < len && previousData[fromLeft] === nextData[fromLeft] ) {
|
2013-01-16 21:51:05 +00:00
|
|
|
++fromLeft;
|
|
|
|
}
|
|
|
|
// Count same characters from right
|
|
|
|
while (
|
|
|
|
fromRight < len - fromLeft &&
|
2013-07-15 21:57:40 +00:00
|
|
|
previousData[previousData.length - 1 - fromRight] ===
|
|
|
|
nextData[nextData.length - 1 - fromRight]
|
2013-01-16 21:51:05 +00:00
|
|
|
) {
|
|
|
|
++fromRight;
|
|
|
|
}
|
2013-07-15 21:57:40 +00:00
|
|
|
data = nextData.slice( fromLeft, nextData.length - fromRight );
|
2013-01-16 21:51:05 +00:00
|
|
|
// Get annotations to the left of new content and apply
|
2013-07-17 15:49:16 +00:00
|
|
|
annotations = this.model.getDocument().data.getAnnotationsFromOffset( nodeOffset + 1 + fromLeft );
|
2013-01-16 21:51:05 +00:00
|
|
|
if ( annotations.getLength() ) {
|
2013-07-17 15:49:16 +00:00
|
|
|
annotationsLeft = this.model.getDocument().data.getAnnotationsFromOffset( nodeOffset + fromLeft );
|
|
|
|
annotationsRight = this.model.getDocument().data.getAnnotationsFromOffset( nodeOffset + 1 + previousData.length - fromRight );
|
|
|
|
for ( i = 0, length = annotations.getLength(); i < length; i++ ) {
|
|
|
|
annotation = annotations.get( i );
|
2013-09-27 10:30:29 +00:00
|
|
|
annotationIndex = annotations.getIndex( i );
|
2013-07-17 15:49:16 +00:00
|
|
|
if ( annotation.constructor.static.splitOnWordbreak ) {
|
|
|
|
dataString = new ve.dm.DataString( nextData );
|
|
|
|
if (
|
|
|
|
// if no annotation to the right, check for wordbreak
|
|
|
|
(
|
2013-09-27 10:30:29 +00:00
|
|
|
!annotationsRight.containsIndex( annotationIndex ) &&
|
2013-07-17 15:49:16 +00:00
|
|
|
unicodeJS.wordbreak.isBreak( dataString, fromLeft )
|
|
|
|
) ||
|
|
|
|
// if no annotation to the left, check for wordbreak
|
|
|
|
(
|
2013-09-27 10:30:29 +00:00
|
|
|
!annotationsLeft.containsIndex( annotationIndex ) &&
|
2013-07-17 15:49:16 +00:00
|
|
|
unicodeJS.wordbreak.isBreak( dataString, nextData.length - fromRight )
|
|
|
|
)
|
|
|
|
) {
|
|
|
|
annotations.removeAt( i );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-10-04 14:27:00 +00:00
|
|
|
ve.dm.Document.static.addAnnotationsToData( data, annotations );
|
2013-01-16 21:51:05 +00:00
|
|
|
}
|
|
|
|
newRange = next.range;
|
|
|
|
if ( newRange.isCollapsed() ) {
|
|
|
|
newRange = new ve.Range( this.getNearestCorrectOffset( newRange.start, 1 ) );
|
|
|
|
}
|
2013-09-04 22:24:08 +00:00
|
|
|
|
2013-01-16 21:51:05 +00:00
|
|
|
if ( data.length > 0 ) {
|
2013-10-01 02:57:18 +00:00
|
|
|
this.changeModel(
|
2013-09-04 22:24:08 +00:00
|
|
|
ve.dm.Transaction.newFromInsertion(
|
|
|
|
this.documentView.model, nodeOffset + 1 + fromLeft,
|
|
|
|
data
|
|
|
|
),
|
|
|
|
newRange
|
|
|
|
);
|
2013-01-16 21:51:05 +00:00
|
|
|
}
|
2013-07-15 21:57:40 +00:00
|
|
|
if ( fromLeft + fromRight < previousData.length ) {
|
2013-10-01 02:57:18 +00:00
|
|
|
this.changeModel(
|
2013-01-16 21:51:05 +00:00
|
|
|
ve.dm.Transaction.newFromRemoval(
|
|
|
|
this.documentView.model,
|
|
|
|
new ve.Range(
|
|
|
|
data.length + nodeOffset + 1 + fromLeft,
|
2013-09-04 22:24:08 +00:00
|
|
|
data.length + nodeOffset + 1 +
|
|
|
|
previousData.length - fromRight
|
2013-01-16 21:51:05 +00:00
|
|
|
)
|
|
|
|
),
|
|
|
|
newRange
|
|
|
|
);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2013-04-15 17:54:49 +00:00
|
|
|
/*! Relocation */
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Start a relocation action.
|
|
|
|
*
|
|
|
|
* @see ve.ce.RelocatableNode
|
|
|
|
*
|
|
|
|
* @method
|
|
|
|
* @param {ve.ce.Node} node Node being relocated
|
|
|
|
*/
|
|
|
|
ve.ce.Surface.prototype.startRelocation = function ( node ) {
|
|
|
|
this.relocating = node;
|
|
|
|
this.emit( 'relocationStart', node );
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Complete a relocation action.
|
|
|
|
*
|
|
|
|
* @see ve.ce.RelocatableNode
|
|
|
|
*
|
|
|
|
* @method
|
|
|
|
* @param {ve.ce.Node} node Node being relocated
|
|
|
|
*/
|
|
|
|
ve.ce.Surface.prototype.endRelocation = function () {
|
|
|
|
this.emit( 'relocationEnd', this.relocating );
|
|
|
|
this.relocating = null;
|
|
|
|
};
|
|
|
|
|
2013-01-16 21:51:05 +00:00
|
|
|
/*! Utilities */
|
|
|
|
|
2013-03-25 23:15:14 +00:00
|
|
|
/**
|
|
|
|
* @method
|
|
|
|
*/
|
|
|
|
ve.ce.Surface.prototype.handleLeftOrRightArrowKey = function ( e ) {
|
2013-06-01 04:53:33 +00:00
|
|
|
var selection, range, direction;
|
2013-03-25 23:15:14 +00:00
|
|
|
// On Mac OS pressing Command (metaKey) + Left/Right is same as pressing Home/End.
|
|
|
|
// As we are not able to handle it programmatically (because we don't know at which offsets
|
|
|
|
// lines starts and ends) let it happen natively.
|
|
|
|
if ( e.metaKey ) {
|
|
|
|
return;
|
|
|
|
}
|
The Great ve.ui.Surface refactor of 2013
Prologue:
Farewell ve.Editor my good chap… Oh, hey there HTML frames - I didn't
see you there! In a world where iframes are outlaws, and symbols like
document and window are global, there were more than a few assumptions
about which document or window was being used. But fear not - for this
commit (probably) tracks them all down, leaving a trail of
iframe-compatible awesomeness in its wake. With the great ve.ui.Surface
now able to be used inside of iframes, let the reference editing
commence. But there, lurking in the darkness is a DM issue so fierce it
may take Roan and/or Ed up to 3 whole hours to sort it out.
Note to Roan and/or Ed:
Editing references seems to work fine, but when saving the page there
are "no changes" which is a reasonable indication to the contrary.
Objectives:
* Make it possible to have multiple surfaces be instantiated, get along
nicely, and be embedded inside of iframes if needed.
* Make reference content editable within a dialog
Approach:
* Move what's left of ve.Editor to ve.ui.Surface and essentially
obliterate all use of it
* Make even more stuff inherit from ve.Element (long live this.$$)
* Use the correct document or window anywhere it was being assumed to be
the top level one
* Resolve stacking order issues by removing the excessive use of z-index
and introducing global and local overlay elements for each editor
* Add a surface to the reference dialog, load up the reference contents
and save them back on apply
* Actually destroy what we create in ce and ui surfaces
* Add recursive frame offset calculation method to ve.Element
* Moved ve.ce.Surface's getSelectionRect method to the prototype
Bonus:
* Move ve.ce.DocumentNode.css contents to ve.ce.Node.css (not sure why it
was separate in the first place, but I'm likely the one to blame)
* Fix blatant lies in documentation
* Whitespace cleanup here and there
* Get rid of ve.ui.Window overlays - not used or needed
Change-Id: Iede83e7d24f7cb249b6ba3dc45d770445b862e08
2013-05-20 22:45:50 +00:00
|
|
|
|
2013-03-25 23:15:14 +00:00
|
|
|
// Selection is going to be displayed programmatically so prevent default browser behaviour
|
|
|
|
e.preventDefault();
|
2013-09-07 01:03:10 +00:00
|
|
|
// TODO: onDocumentKeyDown did this already
|
|
|
|
this.surfaceObserver.stopTimerLoop();
|
|
|
|
this.incRenderLock();
|
|
|
|
try {
|
|
|
|
// TODO: onDocumentKeyDown did this already
|
|
|
|
this.surfaceObserver.pollOnce();
|
|
|
|
} finally {
|
|
|
|
this.decRenderLock();
|
|
|
|
}
|
2013-03-25 23:15:14 +00:00
|
|
|
selection = this.model.getSelection();
|
2013-11-01 19:45:59 +00:00
|
|
|
if ( this.$( e.target ).css( 'direction' ) === 'rtl' ) {
|
2013-05-27 22:14:59 +00:00
|
|
|
// If the language direction is RTL, switch left/right directions:
|
2013-10-09 20:09:59 +00:00
|
|
|
direction = e.keyCode === OO.ui.Keys.LEFT ? 1 : -1;
|
2013-05-27 22:14:59 +00:00
|
|
|
} else {
|
2013-10-09 20:09:59 +00:00
|
|
|
direction = e.keyCode === OO.ui.Keys.LEFT ? -1 : 1;
|
2013-05-27 22:14:59 +00:00
|
|
|
}
|
2013-04-03 22:59:46 +00:00
|
|
|
|
2013-06-01 04:53:33 +00:00
|
|
|
range = this.getDocument().getRelativeRange(
|
|
|
|
selection,
|
|
|
|
direction,
|
|
|
|
( e.altKey === true || e.ctrlKey === true ) ? 'word' : 'character',
|
|
|
|
e.shiftKey
|
|
|
|
);
|
2013-10-15 18:36:02 +00:00
|
|
|
this.model.setSelection( range );
|
2013-09-07 01:03:10 +00:00
|
|
|
// TODO: onDocumentKeyDown does this anyway
|
|
|
|
this.surfaceObserver.startTimerLoop();
|
|
|
|
this.surfaceObserver.pollOnce();
|
2013-03-25 23:15:14 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @method
|
|
|
|
*/
|
|
|
|
ve.ce.Surface.prototype.handleUpOrDownArrowKey = function ( e ) {
|
2013-06-28 22:37:26 +00:00
|
|
|
var selection, rangySelection, rangyRange, range, $element, nativeSel;
|
2013-03-25 23:15:14 +00:00
|
|
|
if ( !$.browser.msie ) {
|
2013-06-28 22:37:26 +00:00
|
|
|
// Firefox doesn't update its internal reference of the appropriate cursor position
|
|
|
|
// on the next or previous lines when the cursor is moved programmatically.
|
|
|
|
// By wiggling the selection, Firefox scraps its internal reference.
|
|
|
|
nativeSel = window.getSelection();
|
|
|
|
nativeSel.modify( 'extend', 'right', 'character' );
|
|
|
|
nativeSel.modify( 'extend', 'left', 'character' );
|
2013-03-25 23:15:14 +00:00
|
|
|
return;
|
|
|
|
}
|
2013-09-07 01:03:10 +00:00
|
|
|
// TODO: onDocumentKeyDown did this already
|
|
|
|
this.surfaceObserver.stopTimerLoop();
|
|
|
|
// TODO: onDocumentKeyDown did this already
|
|
|
|
this.surfaceObserver.pollOnce();
|
|
|
|
|
2013-03-25 23:15:14 +00:00
|
|
|
selection = this.model.getSelection();
|
The Great ve.ui.Surface refactor of 2013
Prologue:
Farewell ve.Editor my good chap… Oh, hey there HTML frames - I didn't
see you there! In a world where iframes are outlaws, and symbols like
document and window are global, there were more than a few assumptions
about which document or window was being used. But fear not - for this
commit (probably) tracks them all down, leaving a trail of
iframe-compatible awesomeness in its wake. With the great ve.ui.Surface
now able to be used inside of iframes, let the reference editing
commence. But there, lurking in the darkness is a DM issue so fierce it
may take Roan and/or Ed up to 3 whole hours to sort it out.
Note to Roan and/or Ed:
Editing references seems to work fine, but when saving the page there
are "no changes" which is a reasonable indication to the contrary.
Objectives:
* Make it possible to have multiple surfaces be instantiated, get along
nicely, and be embedded inside of iframes if needed.
* Make reference content editable within a dialog
Approach:
* Move what's left of ve.Editor to ve.ui.Surface and essentially
obliterate all use of it
* Make even more stuff inherit from ve.Element (long live this.$$)
* Use the correct document or window anywhere it was being assumed to be
the top level one
* Resolve stacking order issues by removing the excessive use of z-index
and introducing global and local overlay elements for each editor
* Add a surface to the reference dialog, load up the reference contents
and save them back on apply
* Actually destroy what we create in ce and ui surfaces
* Add recursive frame offset calculation method to ve.Element
* Moved ve.ce.Surface's getSelectionRect method to the prototype
Bonus:
* Move ve.ce.DocumentNode.css contents to ve.ce.Node.css (not sure why it
was separate in the first place, but I'm likely the one to blame)
* Fix blatant lies in documentation
* Whitespace cleanup here and there
* Get rid of ve.ui.Window overlays - not used or needed
Change-Id: Iede83e7d24f7cb249b6ba3dc45d770445b862e08
2013-05-20 22:45:50 +00:00
|
|
|
rangySelection = rangy.getSelection( this.$document[0] );
|
2013-03-25 23:15:14 +00:00
|
|
|
// Perform programatic handling only for selection that is expanded and backwards according to
|
|
|
|
// model data but not according to browser data.
|
|
|
|
if ( !selection.isCollapsed() && selection.isBackwards() && !rangySelection.isBackwards() ) {
|
2013-11-01 19:45:59 +00:00
|
|
|
$element = this.$( this.documentView.getSlugAtOffset( selection.to ) );
|
2013-03-26 06:10:17 +00:00
|
|
|
if ( !$element ) {
|
2013-11-01 19:45:59 +00:00
|
|
|
$element = this.$( '<span>' )
|
2013-05-14 23:45:42 +00:00
|
|
|
.html( ' ' )
|
2013-12-06 02:34:44 +00:00
|
|
|
.css( { 'width': '0px', 'display': 'none' } );
|
2013-03-25 23:15:14 +00:00
|
|
|
rangySelection.anchorNode.splitText( rangySelection.anchorOffset );
|
|
|
|
rangySelection.anchorNode.parentNode.insertBefore(
|
2013-03-26 06:10:17 +00:00
|
|
|
$element[0],
|
2013-03-25 23:15:14 +00:00
|
|
|
rangySelection.anchorNode.nextSibling
|
|
|
|
);
|
|
|
|
}
|
The Great ve.ui.Surface refactor of 2013
Prologue:
Farewell ve.Editor my good chap… Oh, hey there HTML frames - I didn't
see you there! In a world where iframes are outlaws, and symbols like
document and window are global, there were more than a few assumptions
about which document or window was being used. But fear not - for this
commit (probably) tracks them all down, leaving a trail of
iframe-compatible awesomeness in its wake. With the great ve.ui.Surface
now able to be used inside of iframes, let the reference editing
commence. But there, lurking in the darkness is a DM issue so fierce it
may take Roan and/or Ed up to 3 whole hours to sort it out.
Note to Roan and/or Ed:
Editing references seems to work fine, but when saving the page there
are "no changes" which is a reasonable indication to the contrary.
Objectives:
* Make it possible to have multiple surfaces be instantiated, get along
nicely, and be embedded inside of iframes if needed.
* Make reference content editable within a dialog
Approach:
* Move what's left of ve.Editor to ve.ui.Surface and essentially
obliterate all use of it
* Make even more stuff inherit from ve.Element (long live this.$$)
* Use the correct document or window anywhere it was being assumed to be
the top level one
* Resolve stacking order issues by removing the excessive use of z-index
and introducing global and local overlay elements for each editor
* Add a surface to the reference dialog, load up the reference contents
and save them back on apply
* Actually destroy what we create in ce and ui surfaces
* Add recursive frame offset calculation method to ve.Element
* Moved ve.ce.Surface's getSelectionRect method to the prototype
Bonus:
* Move ve.ce.DocumentNode.css contents to ve.ce.Node.css (not sure why it
was separate in the first place, but I'm likely the one to blame)
* Fix blatant lies in documentation
* Whitespace cleanup here and there
* Get rid of ve.ui.Window overlays - not used or needed
Change-Id: Iede83e7d24f7cb249b6ba3dc45d770445b862e08
2013-05-20 22:45:50 +00:00
|
|
|
rangyRange = rangy.createRange( this.$document[0] );
|
2013-03-26 06:10:17 +00:00
|
|
|
rangyRange.selectNode( $element[0] );
|
|
|
|
rangySelection.setSingleRange( rangyRange );
|
2013-05-06 11:34:32 +00:00
|
|
|
setTimeout( ve.bind( function () {
|
ve.ce.ProtectedNode
Objective:
Generalize the shield and phantom magic, so we can use it for pretty much
any node we like. Usually this will be used with generated content nodes,
but also with aliens (of course) and possible other stuff in the future.
Bonus:
Also fixes a bug in DM that would crash VE when you selected to the end
and hit backspace.
Changes:
*.php
* Added links to files
aliens.html
* Added attributes to aliens to make them aliens again
ve.ce.AlienNode.js
* Moved shield and phantom functionality to ve.ce.ProtectedNode
ve.ce.AlienNode.js, ve.ce.MWReferenceListNode.js,
ve.ce.MWReferenceNode.js, ve.ce.MWTemplateNode.js
* Mixed in ve.ce.ProtectedNode
ve.ce.Node.css
* Reorganized styles and updated class names
* Added simple light blue hover with outline (using inset box shadow) for
protected nodes, same style as before for aliens
ve.ce.Surface.css
* Moved phantom styles to ve.ce.Node.css
ve.ce.BranchNode.js
* Moved call to setLive(false) to happen before detach() so that the
surface object is still available and events can be disconnected
ve.ce.BranchNode.js, ve.ce.Document.js, ve.ce.js, ve.ce.Surface.js, ve.ce.SurfaceObserver.js
* Adjusted CSS class names
ve.ce.Node.js
* Moved shield template to ve.ce.ProtectedNode
ve.ce.ProtectedNode.js
* New class, mix into another class to protect it from editing
ve.ce.RelocatableNode.js
* Renamed temporary surface property to relocatingSurface to avoid
confusion when debugging
ve.ce.Surface.js
* Moved phantom template to ve.ce.ProtectedNode
ve.dm.Transaction.js
* Fixed bug where most of the internal list was being deleted when the
end of the document was selected and the user pressed backspace
Change-Id: I2468b16e1ba6785ad298e38190e33493135719c3
2013-05-07 00:07:01 +00:00
|
|
|
if ( !$element.hasClass( 've-ce-branchNode-slug' ) ) {
|
2013-03-26 06:10:17 +00:00
|
|
|
$element.remove();
|
2013-03-25 23:15:14 +00:00
|
|
|
}
|
2013-09-07 01:03:10 +00:00
|
|
|
this.surfaceObserver.pollOnce();
|
2013-05-06 11:34:32 +00:00
|
|
|
if ( e.shiftKey === true ) { // expanded range
|
2013-03-25 23:15:14 +00:00
|
|
|
range = new ve.Range( selection.from, this.model.getSelection().to );
|
|
|
|
} else { // collapsed range (just a cursor)
|
|
|
|
range = new ve.Range( this.model.getSelection().to );
|
|
|
|
}
|
2013-10-15 18:36:02 +00:00
|
|
|
this.model.setSelection( range );
|
2013-09-07 01:03:10 +00:00
|
|
|
this.surfaceObserver.pollOnce();
|
2013-03-25 23:15:14 +00:00
|
|
|
}, this ), 0 );
|
|
|
|
} else {
|
2013-09-07 01:03:10 +00:00
|
|
|
// TODO: onDocumentKeyDown does this anyway
|
|
|
|
this.surfaceObserver.startTimerLoop();
|
|
|
|
|
|
|
|
this.surfaceObserver.pollOnce();
|
2013-03-25 23:15:14 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2013-01-16 21:51:05 +00:00
|
|
|
/**
|
|
|
|
* Handle insertion of content.
|
|
|
|
*
|
|
|
|
* @method
|
|
|
|
*/
|
|
|
|
ve.ce.Surface.prototype.handleInsertion = function () {
|
|
|
|
var slug, data, range, annotations, insertionAnnotations, placeholder,
|
2013-03-20 22:35:05 +00:00
|
|
|
selection = this.model.getSelection(), documentModel = this.model.getDocument();
|
2013-01-16 21:51:05 +00:00
|
|
|
|
|
|
|
// Handles removing expanded selection before inserting new text
|
|
|
|
if ( !selection.isCollapsed() ) {
|
|
|
|
// Pull annotations from the first character in the selection
|
2013-03-20 22:35:05 +00:00
|
|
|
annotations = documentModel.data.getAnnotationsFromRange(
|
2013-01-16 21:51:05 +00:00
|
|
|
new ve.Range( selection.start, selection.start + 1 )
|
|
|
|
);
|
|
|
|
this.model.change(
|
|
|
|
ve.dm.Transaction.newFromRemoval( this.documentView.model, selection ),
|
|
|
|
new ve.Range( selection.start )
|
|
|
|
);
|
|
|
|
this.surfaceObserver.clear();
|
|
|
|
selection = this.model.getSelection();
|
|
|
|
this.model.setInsertionAnnotations( annotations );
|
|
|
|
}
|
2013-05-01 18:36:32 +00:00
|
|
|
|
2013-03-20 22:35:05 +00:00
|
|
|
insertionAnnotations = this.model.getInsertionAnnotations() ||
|
|
|
|
new ve.dm.AnnotationSet( documentModel.getStore() );
|
2013-05-01 18:36:32 +00:00
|
|
|
|
2013-01-16 21:51:05 +00:00
|
|
|
if ( selection.isCollapsed() ) {
|
|
|
|
slug = this.documentView.getSlugAtOffset( selection.start );
|
2013-07-15 23:29:30 +00:00
|
|
|
// Always pawn in a slug
|
|
|
|
if ( slug || this.needsPawn( selection, insertionAnnotations ) ) {
|
2013-05-01 18:36:32 +00:00
|
|
|
placeholder = '♙';
|
2013-01-16 21:51:05 +00:00
|
|
|
if ( !insertionAnnotations.isEmpty() ) {
|
2013-05-01 18:36:32 +00:00
|
|
|
placeholder = [placeholder, insertionAnnotations.getIndexes()];
|
2013-01-16 21:51:05 +00:00
|
|
|
}
|
|
|
|
// is this a slug and if so, is this a block slug?
|
2013-03-20 22:35:05 +00:00
|
|
|
if ( slug && documentModel.data.isStructuralOffset( selection.start ) ) {
|
2013-01-16 21:51:05 +00:00
|
|
|
range = new ve.Range( selection.start + 1, selection.start + 2 );
|
2013-12-06 02:34:44 +00:00
|
|
|
data = [{ 'type': 'paragraph' }, placeholder, { 'type': '/paragraph' }];
|
2013-01-16 21:51:05 +00:00
|
|
|
} else {
|
|
|
|
range = new ve.Range( selection.start, selection.start + 1 );
|
|
|
|
data = [placeholder];
|
|
|
|
}
|
|
|
|
this.model.change(
|
|
|
|
ve.dm.Transaction.newFromInsertion(
|
|
|
|
this.documentView.model, selection.start, data
|
|
|
|
),
|
|
|
|
range
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-07 01:03:10 +00:00
|
|
|
this.surfaceObserver.stopTimerLoop();
|
|
|
|
this.surfaceObserver.pollOnce();
|
2013-01-16 21:51:05 +00:00
|
|
|
};
|
|
|
|
|
Make use of new jshint options
* Restricting "camelcase":
No changes, we were passing all of these already
* Explicitly unrestricting "forin" and "plusplus"
These are off by default in node-jshint, but some distro of jshint
and editors that use their own wrapper around jshint instead of
node-jshint (Eclipse?) may have different defaults. Therefor
setting them to false explicitly. This also serves as a reminder
for the future so we'll always know we don't pass that, in case
we would want to change that.
* Fix order ("quotemark" before "regexp")
* Restricting "unused"
We're not passing all of this, which is why I've set it to false
for now. But I did put it in .jshintrc as placeholder.
I've fixed most of them, there's some left where there is no clean
solution.
* While at it fix a few issues:
- Unused variables ($target, $window)
- Bad practices (using jQuery context for find instead of creation)
- Redundant /*global */ comments
- Parameters that are not used and don't have documentation either
- Lines longer than 100 chars @ 4 spaces/tab
* Note:
- ve.ce.Surface.prototype.onChange takes two arguments but never
uses the former. And even the second one can be null/undefined.
Aside from that, the .change() function emits
another event for the transaction already. Looks like this
should be refactored a bit, two more separated events probably
or one that is actually used better.
- Also cleaned up a lot of comments, some of which were missing,
others were incorrect
- Reworked the contentChange event so we are no longer using the
word new as an object key; expanded a complex object into multiple
arguments being passed through the event to make it easier to work
with and document
Change-Id: I8490815a508c6c379d5f9a743bb4aefd14576aa6
2012-08-07 06:02:18 +00:00
|
|
|
/**
|
Major UI refactoring and improvements
Objective:
Refactor UI widgets, improve usability and accessibility of menus, general cleanup and style improvements.
Extras:
Fixed documentation in a few other files to make descriptions of jQuery event arguments more consistent, classes inherit correctly, and made use of the @cfg functionality in jsduck.
Changes:
.docs/config.json
* Added window, HTMLDocument, HTMLElement, DocumentFragment and XMLHttpRequest to externals, so jsduck doesn't throw warnings when they are used
demos/ve/index.php, modules/ve/test/index.php, VisualEditor.php
* Moved widgets above tools (since tools use widgets)
demos/ve/index.php
* Refactored widget initialization to use options
* Renamed variables to match widget names
ve.init.mw.ViewPageTarget.css
* Adjusted text sizes to make widgets work normally
* Added margins for buttons in toolbar (since button widgets
don't have any)
* Removed styles for init buttons (button widgets now)
ve.init.mw.ViewPageTarget.js
* Switched to using button widgets (involved moving things around
a bit)
ve.ui.LinkInspector.js, ve.ui.MWLinkInspector.js
* Renamed static property "inputWidget" to
"linkTargetInputWidget" to better reflect the required base class
for the properties value
icons.ai, check.png, check.svg
* Added "check" icon, used in menu right now to show which item
is selected
ve.ui.Icons-raster.css, ve.ui.Icons-vector.css
* Added check icon
* Removed :before pseudo selectors from most of the icon classes (not need by button tool anymore, makes them more reusable now)
ve.ui.Tool.css
* Adjusted drop down tool styles so menu appears below, instead
of on top, of the label
* Adjusted paragraph font size to better match actual content
* Updated class names to still work with menu widget changes
(items are their own widgets now)
* Updated selectors as per changes in the structure of button tools
ve.ui.Widget.css
* Added styles for buttons and menu items
* Adjusted menu styles
ve.ui.*ButtonTool.js
* Added config options argument passthrough
ve.ui.ButtonTool.js
* Moved var statement to the top inside constructor
* Switched to using "a" tag to get cross-browser :active support
* Added icon to inside of button to make icon styles more reusable
* Removed disabled support (now provided by widget parent class)
ve.ui.FormatDropDownTool.js
* Updated options initialization to construct menu item objects
* Modified handling of items to account for changes in menu and
item classes
* Optimized onUpdateState method a bit, adding early exit to
inner loop
ve.ui.ButtonTool.js, ve.ui.DropdownTool.js, ve.ui.Context.js,
ve.ui.Frame, ve.ui.Tool.js, ve.ui.Widget.js
* Added chain ability to non-getter methods
ve.ui.DropdownTool.js
* Removed items argument to constructor
* Updated code as per changes in menu class
* Fixed inconsistent naming of event handler methods
* Removed item event handling (now handled by items directly)
* Made use of this.$$ to ensure tool works in other frames
ve.ui.Tool.js
* Made tools inherit from widget
* Moved trigger registry event handler to a method
ve.ui.Context.js
* Switched from using menu to contain toolbar to a simple wrapper
ve.ui.js
* Added get$$ method, a convenience function for binding jQuery
to a specific document context
ve.ui.*Widget.js
* Switched to using a config options object instead of individual arguments
* Added options
* Factored out flags and labels into their own classes
* Refactored value setting methods for inputs
ve.ui.MenuWidget.js, ve.ui.MenuItemWidget.js
* Broke items out into their own classes
* Redesigned API
* Updated code that uses these classes
* Added support for keyboard interaction
* Made items flash when selected (delaying the hiding of the menu for 200ms)
ve.ui.LinkTargetInputWidget.js, ve.ui.MWLinkTargetInputWidget
* Refactored annotation setting methods
Change-Id: I7769bd5a5b79f1ab36f258ef9f2be583ca503ce6
2013-02-20 23:25:12 +00:00
|
|
|
* Handle enter key down events.
|
Make use of new jshint options
* Restricting "camelcase":
No changes, we were passing all of these already
* Explicitly unrestricting "forin" and "plusplus"
These are off by default in node-jshint, but some distro of jshint
and editors that use their own wrapper around jshint instead of
node-jshint (Eclipse?) may have different defaults. Therefor
setting them to false explicitly. This also serves as a reminder
for the future so we'll always know we don't pass that, in case
we would want to change that.
* Fix order ("quotemark" before "regexp")
* Restricting "unused"
We're not passing all of this, which is why I've set it to false
for now. But I did put it in .jshintrc as placeholder.
I've fixed most of them, there's some left where there is no clean
solution.
* While at it fix a few issues:
- Unused variables ($target, $window)
- Bad practices (using jQuery context for find instead of creation)
- Redundant /*global */ comments
- Parameters that are not used and don't have documentation either
- Lines longer than 100 chars @ 4 spaces/tab
* Note:
- ve.ce.Surface.prototype.onChange takes two arguments but never
uses the former. And even the second one can be null/undefined.
Aside from that, the .change() function emits
another event for the transaction already. Looks like this
should be refactored a bit, two more separated events probably
or one that is actually used better.
- Also cleaned up a lot of comments, some of which were missing,
others were incorrect
- Reworked the contentChange event so we are no longer using the
word new as an object key; expanded a complex object into multiple
arguments being passed through the event to make it easier to work
with and document
Change-Id: I8490815a508c6c379d5f9a743bb4aefd14576aa6
2012-08-07 06:02:18 +00:00
|
|
|
*
|
|
|
|
* @method
|
Major UI refactoring and improvements
Objective:
Refactor UI widgets, improve usability and accessibility of menus, general cleanup and style improvements.
Extras:
Fixed documentation in a few other files to make descriptions of jQuery event arguments more consistent, classes inherit correctly, and made use of the @cfg functionality in jsduck.
Changes:
.docs/config.json
* Added window, HTMLDocument, HTMLElement, DocumentFragment and XMLHttpRequest to externals, so jsduck doesn't throw warnings when they are used
demos/ve/index.php, modules/ve/test/index.php, VisualEditor.php
* Moved widgets above tools (since tools use widgets)
demos/ve/index.php
* Refactored widget initialization to use options
* Renamed variables to match widget names
ve.init.mw.ViewPageTarget.css
* Adjusted text sizes to make widgets work normally
* Added margins for buttons in toolbar (since button widgets
don't have any)
* Removed styles for init buttons (button widgets now)
ve.init.mw.ViewPageTarget.js
* Switched to using button widgets (involved moving things around
a bit)
ve.ui.LinkInspector.js, ve.ui.MWLinkInspector.js
* Renamed static property "inputWidget" to
"linkTargetInputWidget" to better reflect the required base class
for the properties value
icons.ai, check.png, check.svg
* Added "check" icon, used in menu right now to show which item
is selected
ve.ui.Icons-raster.css, ve.ui.Icons-vector.css
* Added check icon
* Removed :before pseudo selectors from most of the icon classes (not need by button tool anymore, makes them more reusable now)
ve.ui.Tool.css
* Adjusted drop down tool styles so menu appears below, instead
of on top, of the label
* Adjusted paragraph font size to better match actual content
* Updated class names to still work with menu widget changes
(items are their own widgets now)
* Updated selectors as per changes in the structure of button tools
ve.ui.Widget.css
* Added styles for buttons and menu items
* Adjusted menu styles
ve.ui.*ButtonTool.js
* Added config options argument passthrough
ve.ui.ButtonTool.js
* Moved var statement to the top inside constructor
* Switched to using "a" tag to get cross-browser :active support
* Added icon to inside of button to make icon styles more reusable
* Removed disabled support (now provided by widget parent class)
ve.ui.FormatDropDownTool.js
* Updated options initialization to construct menu item objects
* Modified handling of items to account for changes in menu and
item classes
* Optimized onUpdateState method a bit, adding early exit to
inner loop
ve.ui.ButtonTool.js, ve.ui.DropdownTool.js, ve.ui.Context.js,
ve.ui.Frame, ve.ui.Tool.js, ve.ui.Widget.js
* Added chain ability to non-getter methods
ve.ui.DropdownTool.js
* Removed items argument to constructor
* Updated code as per changes in menu class
* Fixed inconsistent naming of event handler methods
* Removed item event handling (now handled by items directly)
* Made use of this.$$ to ensure tool works in other frames
ve.ui.Tool.js
* Made tools inherit from widget
* Moved trigger registry event handler to a method
ve.ui.Context.js
* Switched from using menu to contain toolbar to a simple wrapper
ve.ui.js
* Added get$$ method, a convenience function for binding jQuery
to a specific document context
ve.ui.*Widget.js
* Switched to using a config options object instead of individual arguments
* Added options
* Factored out flags and labels into their own classes
* Refactored value setting methods for inputs
ve.ui.MenuWidget.js, ve.ui.MenuItemWidget.js
* Broke items out into their own classes
* Redesigned API
* Updated code that uses these classes
* Added support for keyboard interaction
* Made items flash when selected (delaying the hiding of the menu for 200ms)
ve.ui.LinkTargetInputWidget.js, ve.ui.MWLinkTargetInputWidget
* Refactored annotation setting methods
Change-Id: I7769bd5a5b79f1ab36f258ef9f2be583ca503ce6
2013-02-20 23:25:12 +00:00
|
|
|
* @param {jQuery.Event} e Enter key down event
|
Make use of new jshint options
* Restricting "camelcase":
No changes, we were passing all of these already
* Explicitly unrestricting "forin" and "plusplus"
These are off by default in node-jshint, but some distro of jshint
and editors that use their own wrapper around jshint instead of
node-jshint (Eclipse?) may have different defaults. Therefor
setting them to false explicitly. This also serves as a reminder
for the future so we'll always know we don't pass that, in case
we would want to change that.
* Fix order ("quotemark" before "regexp")
* Restricting "unused"
We're not passing all of this, which is why I've set it to false
for now. But I did put it in .jshintrc as placeholder.
I've fixed most of them, there's some left where there is no clean
solution.
* While at it fix a few issues:
- Unused variables ($target, $window)
- Bad practices (using jQuery context for find instead of creation)
- Redundant /*global */ comments
- Parameters that are not used and don't have documentation either
- Lines longer than 100 chars @ 4 spaces/tab
* Note:
- ve.ce.Surface.prototype.onChange takes two arguments but never
uses the former. And even the second one can be null/undefined.
Aside from that, the .change() function emits
another event for the transaction already. Looks like this
should be refactored a bit, two more separated events probably
or one that is actually used better.
- Also cleaned up a lot of comments, some of which were missing,
others were incorrect
- Reworked the contentChange event so we are no longer using the
word new as an object key; expanded a complex object into multiple
arguments being passed through the event to make it easier to work
with and document
Change-Id: I8490815a508c6c379d5f9a743bb4aefd14576aa6
2012-08-07 06:02:18 +00:00
|
|
|
*/
|
Kranitor #1: On-boarding
'''Kranitor commits''' are commits by Krinkle with his janitor hat on.
Must never contain functional changes mixed with miscellaneous changes.
.gitignore:
* Add .DS_Store to the ignore list so that browsing the directories
on Mac OS X, will not add these files to the list of untracked
files.
* Fix missing newline at end of file
.jshintrc
* raises -> throws
* +module (QUnit.module)
* remove 'Node' (as of node-jshint 1.7.2 this is now part of
'browser:true', as it should be)
Authors:
* Adding myself
MWExtension/VisualEditor.php
* Fix default value of wgVisualEditorParsoidURL to not
point to the experimental instance in WMF Labs.
Issues:
* ve.ce.TextNode:
- Fix TODO: Don't perform a useless clone of an already-jQuerified object.
- Use .html() to set html content instead of encapsulating between
two strings. This is slightly faster but more importantly safer,
and prevents situations where the resulting jQuery collection
actually contains 2 elements instead of 1, thus messing up
what .contents() is iterating over.
* ve.ce.Document.test.js
- Fix: ReferenceError: assert is not defined
* ve.dm.Document.test.js
- Fix: ReferenceError: assert is not defined
* ve.dm.Transaction.test.js
- Fix: ReferenceError: assert is not defined
* ve.dm.TransactionProcessor.test.js
- Fix: ReferenceError: assert is not defined
* ext.visualEditor.viewPageTarget
- Missing dependency on 'mediawiki.Title'
Code conventions / Misc cleanup
* Various JSHint warnings.
* Whitespace
* jQuery(): Use '<tag>' for element creation,
use '<valid><xml/></valid>' for parsing
* Use the default operator instead of ternary when the condition and
first value are the same.
x = foo ? foo : bar; -> x = foo || bar;
Because contrary to some programming language (PHP...), in JS the
default operator does not enforce a boolean result but returns the
original value, hence it being called the 'default' operator, as
opposed to the 'or' operator.
* No need to call addClass() twice, it takes a space-separated list
(jQuery splits by space and adds if needed)
* Use .on( event[, selector], fn ) instead of the deprecated
routers to it such as .bind(), .delegate() and .live().
All these three are now built-in and fully compatible with .on()
* Add 'XXX:' comments for suspicious code that I don't want to change
as part of a clean up commit.
* Remove unused variables (several var x = this; where x was not
used anywhere, possibly from boilerplate copy/paste)
* Follows-up Trevor's commit that converts test suites to the new
QUnit format. Also removed the globals since we no longer use those
any more.
Change-Id: I7e37c9bff812e371c7f65a6fd85d9e2af3e0a22f
2012-07-27 08:43:33 +00:00
|
|
|
ve.ce.Surface.prototype.handleEnter = function ( e ) {
|
2012-08-02 18:46:13 +00:00
|
|
|
var tx, outerParent, outerChildrenCount, list,
|
|
|
|
selection = this.model.getSelection(),
|
2012-06-21 00:36:18 +00:00
|
|
|
documentModel = this.model.getDocument(),
|
2012-06-21 04:10:48 +00:00
|
|
|
emptyParagraph = [{ 'type': 'paragraph' }, { 'type': '/paragraph' }],
|
2012-07-19 03:40:49 +00:00
|
|
|
advanceCursor = true,
|
2012-08-02 18:46:13 +00:00
|
|
|
node = this.documentView.getNodeFromOffset( selection.from ),
|
|
|
|
nodeModel = node.getModel(),
|
|
|
|
cursor = selection.from,
|
|
|
|
contentBranchModel = nodeModel.isContent() ? nodeModel.getParent() : nodeModel,
|
|
|
|
contentBranchModelRange = contentBranchModel.getRange(),
|
|
|
|
stack = [],
|
|
|
|
outermostNode = null;
|
2012-06-22 22:05:35 +00:00
|
|
|
|
2012-06-21 00:36:18 +00:00
|
|
|
// Handle removal first
|
2012-06-20 01:20:28 +00:00
|
|
|
if ( selection.from !== selection.to ) {
|
2012-06-21 00:36:18 +00:00
|
|
|
tx = ve.dm.Transaction.newFromRemoval( documentModel, selection );
|
|
|
|
selection = tx.translateRange( selection );
|
2013-10-01 02:57:18 +00:00
|
|
|
// We do want this to propagate to the surface
|
2012-06-21 00:36:18 +00:00
|
|
|
this.model.change( tx, selection );
|
2012-06-20 01:20:28 +00:00
|
|
|
}
|
2012-06-21 03:00:44 +00:00
|
|
|
|
2012-08-02 18:46:13 +00:00
|
|
|
// Handle insertion
|
2012-06-21 03:00:44 +00:00
|
|
|
if (
|
|
|
|
contentBranchModel.getType() !== 'paragraph' &&
|
|
|
|
(
|
|
|
|
cursor === contentBranchModelRange.from ||
|
|
|
|
cursor === contentBranchModelRange.to
|
|
|
|
)
|
|
|
|
) {
|
2012-06-21 00:36:18 +00:00
|
|
|
// If we're at the start/end of something that's not a paragraph, insert a paragraph
|
|
|
|
// before/after
|
|
|
|
if ( cursor === contentBranchModelRange.from ) {
|
|
|
|
tx = ve.dm.Transaction.newFromInsertion(
|
|
|
|
documentModel, contentBranchModel.getOuterRange().from, emptyParagraph
|
|
|
|
);
|
2013-06-27 19:03:43 +00:00
|
|
|
advanceCursor = false;
|
2012-06-21 00:36:18 +00:00
|
|
|
} else if ( cursor === contentBranchModelRange.to ) {
|
|
|
|
tx = ve.dm.Transaction.newFromInsertion(
|
|
|
|
documentModel, contentBranchModel.getOuterRange().to, emptyParagraph
|
|
|
|
);
|
2012-06-20 01:20:28 +00:00
|
|
|
}
|
2013-02-26 01:09:34 +00:00
|
|
|
} else if ( e.shiftKey && contentBranchModel.hasSignificantWhitespace() ) {
|
|
|
|
// Insert newline
|
|
|
|
tx = ve.dm.Transaction.newFromInsertion( documentModel, selection.from, '\n' );
|
2012-06-21 00:36:18 +00:00
|
|
|
} else {
|
|
|
|
// Split
|
2013-02-01 23:35:48 +00:00
|
|
|
node.traverseUpstream( function ( node ) {
|
2012-06-21 00:36:18 +00:00
|
|
|
if ( !node.canBeSplit() ) {
|
|
|
|
return false;
|
2012-06-20 01:20:28 +00:00
|
|
|
}
|
2012-06-21 00:36:18 +00:00
|
|
|
stack.splice(
|
|
|
|
stack.length / 2,
|
|
|
|
0,
|
2012-06-21 01:59:12 +00:00
|
|
|
{ 'type': '/' + node.type },
|
|
|
|
node.model.getClonedElement()
|
2012-06-21 00:36:18 +00:00
|
|
|
);
|
2012-06-21 04:10:48 +00:00
|
|
|
outermostNode = node;
|
2012-06-22 22:05:35 +00:00
|
|
|
if ( e.shiftKey ) {
|
|
|
|
return false;
|
|
|
|
} else {
|
|
|
|
return true;
|
|
|
|
}
|
2012-06-21 00:36:18 +00:00
|
|
|
} );
|
2012-06-22 22:05:35 +00:00
|
|
|
|
2012-07-19 03:40:49 +00:00
|
|
|
outerParent = outermostNode.getModel().getParent();
|
|
|
|
outerChildrenCount = outerParent.getChildren().length;
|
2012-06-22 22:05:35 +00:00
|
|
|
|
2012-06-27 16:29:58 +00:00
|
|
|
if (
|
Make use of new jshint options
* Restricting "camelcase":
No changes, we were passing all of these already
* Explicitly unrestricting "forin" and "plusplus"
These are off by default in node-jshint, but some distro of jshint
and editors that use their own wrapper around jshint instead of
node-jshint (Eclipse?) may have different defaults. Therefor
setting them to false explicitly. This also serves as a reminder
for the future so we'll always know we don't pass that, in case
we would want to change that.
* Fix order ("quotemark" before "regexp")
* Restricting "unused"
We're not passing all of this, which is why I've set it to false
for now. But I did put it in .jshintrc as placeholder.
I've fixed most of them, there's some left where there is no clean
solution.
* While at it fix a few issues:
- Unused variables ($target, $window)
- Bad practices (using jQuery context for find instead of creation)
- Redundant /*global */ comments
- Parameters that are not used and don't have documentation either
- Lines longer than 100 chars @ 4 spaces/tab
* Note:
- ve.ce.Surface.prototype.onChange takes two arguments but never
uses the former. And even the second one can be null/undefined.
Aside from that, the .change() function emits
another event for the transaction already. Looks like this
should be refactored a bit, two more separated events probably
or one that is actually used better.
- Also cleaned up a lot of comments, some of which were missing,
others were incorrect
- Reworked the contentChange event so we are no longer using the
word new as an object key; expanded a complex object into multiple
arguments being passed through the event to make it easier to work
with and document
Change-Id: I8490815a508c6c379d5f9a743bb4aefd14576aa6
2012-08-07 06:02:18 +00:00
|
|
|
// This is a list item
|
|
|
|
outermostNode.type === 'listItem' &&
|
2013-01-16 21:51:05 +00:00
|
|
|
// This is the last list item
|
|
|
|
outerParent.getChildren()[outerChildrenCount - 1] === outermostNode.getModel() &&
|
|
|
|
// There is one child
|
|
|
|
outermostNode.children.length === 1 &&
|
|
|
|
// The child is empty
|
|
|
|
node.model.length === 0
|
|
|
|
) {
|
|
|
|
// Enter was pressed in an empty list item.
|
|
|
|
list = outermostNode.getModel().getParent();
|
2013-05-10 00:47:36 +00:00
|
|
|
if ( list.getChildren().length === 1 ) {
|
|
|
|
// The list item we're about to remove is the only child of the list
|
|
|
|
// Remove the list
|
|
|
|
tx = ve.dm.Transaction.newFromRemoval(
|
|
|
|
documentModel, list.getOuterRange()
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
// Remove the list item
|
|
|
|
tx = ve.dm.Transaction.newFromRemoval(
|
|
|
|
documentModel, outermostNode.getModel().getOuterRange()
|
|
|
|
);
|
|
|
|
this.model.change( tx );
|
|
|
|
selection = tx.translateRange( selection );
|
|
|
|
// Insert a paragraph
|
|
|
|
tx = ve.dm.Transaction.newFromInsertion(
|
|
|
|
documentModel, list.getOuterRange().to, emptyParagraph
|
|
|
|
);
|
|
|
|
}
|
2013-01-16 21:51:05 +00:00
|
|
|
advanceCursor = false;
|
2012-11-28 01:29:09 +00:00
|
|
|
} else {
|
2013-01-16 21:51:05 +00:00
|
|
|
// We must process the transaction first because getRelativeContentOffset can't help us
|
|
|
|
// yet
|
|
|
|
tx = ve.dm.Transaction.newFromInsertion( documentModel, selection.from, stack );
|
2012-11-28 01:29:09 +00:00
|
|
|
}
|
|
|
|
}
|
2013-01-16 21:51:05 +00:00
|
|
|
|
|
|
|
// Commit the transaction
|
|
|
|
this.model.change( tx );
|
2013-05-10 00:47:36 +00:00
|
|
|
selection = tx.translateRange( selection );
|
2013-01-16 21:51:05 +00:00
|
|
|
|
|
|
|
// Now we can move the cursor forward
|
|
|
|
if ( advanceCursor ) {
|
2013-12-02 15:44:28 +00:00
|
|
|
cursor = documentModel.data.getRelativeContentOffset( selection.from, 1 );
|
2013-01-16 21:51:05 +00:00
|
|
|
} else {
|
2013-12-02 15:44:28 +00:00
|
|
|
cursor = documentModel.data.getNearestContentOffset( selection.from );
|
|
|
|
}
|
|
|
|
if ( cursor === -1 ) {
|
|
|
|
// Cursor couldn't be placed in a nearby content node, so create an empty paragraph
|
|
|
|
this.model.change(
|
|
|
|
ve.dm.Transaction.newFromInsertion(
|
|
|
|
documentModel, selection.from, emptyParagraph
|
|
|
|
)
|
2012-11-28 01:29:09 +00:00
|
|
|
);
|
2013-12-02 15:44:28 +00:00
|
|
|
this.model.setSelection( new ve.Range( selection.from + 1 ) );
|
|
|
|
} else {
|
|
|
|
this.model.setSelection( new ve.Range( cursor ) );
|
2012-11-28 01:29:09 +00:00
|
|
|
}
|
2013-01-16 21:51:05 +00:00
|
|
|
// Reset and resume polling
|
|
|
|
this.surfaceObserver.clear();
|
2012-11-28 01:29:09 +00:00
|
|
|
};
|
|
|
|
|
Make use of new jshint options
* Restricting "camelcase":
No changes, we were passing all of these already
* Explicitly unrestricting "forin" and "plusplus"
These are off by default in node-jshint, but some distro of jshint
and editors that use their own wrapper around jshint instead of
node-jshint (Eclipse?) may have different defaults. Therefor
setting them to false explicitly. This also serves as a reminder
for the future so we'll always know we don't pass that, in case
we would want to change that.
* Fix order ("quotemark" before "regexp")
* Restricting "unused"
We're not passing all of this, which is why I've set it to false
for now. But I did put it in .jshintrc as placeholder.
I've fixed most of them, there's some left where there is no clean
solution.
* While at it fix a few issues:
- Unused variables ($target, $window)
- Bad practices (using jQuery context for find instead of creation)
- Redundant /*global */ comments
- Parameters that are not used and don't have documentation either
- Lines longer than 100 chars @ 4 spaces/tab
* Note:
- ve.ce.Surface.prototype.onChange takes two arguments but never
uses the former. And even the second one can be null/undefined.
Aside from that, the .change() function emits
another event for the transaction already. Looks like this
should be refactored a bit, two more separated events probably
or one that is actually used better.
- Also cleaned up a lot of comments, some of which were missing,
others were incorrect
- Reworked the contentChange event so we are no longer using the
word new as an object key; expanded a complex object into multiple
arguments being passed through the event to make it easier to work
with and document
Change-Id: I8490815a508c6c379d5f9a743bb4aefd14576aa6
2012-08-07 06:02:18 +00:00
|
|
|
/**
|
Major UI refactoring and improvements
Objective:
Refactor UI widgets, improve usability and accessibility of menus, general cleanup and style improvements.
Extras:
Fixed documentation in a few other files to make descriptions of jQuery event arguments more consistent, classes inherit correctly, and made use of the @cfg functionality in jsduck.
Changes:
.docs/config.json
* Added window, HTMLDocument, HTMLElement, DocumentFragment and XMLHttpRequest to externals, so jsduck doesn't throw warnings when they are used
demos/ve/index.php, modules/ve/test/index.php, VisualEditor.php
* Moved widgets above tools (since tools use widgets)
demos/ve/index.php
* Refactored widget initialization to use options
* Renamed variables to match widget names
ve.init.mw.ViewPageTarget.css
* Adjusted text sizes to make widgets work normally
* Added margins for buttons in toolbar (since button widgets
don't have any)
* Removed styles for init buttons (button widgets now)
ve.init.mw.ViewPageTarget.js
* Switched to using button widgets (involved moving things around
a bit)
ve.ui.LinkInspector.js, ve.ui.MWLinkInspector.js
* Renamed static property "inputWidget" to
"linkTargetInputWidget" to better reflect the required base class
for the properties value
icons.ai, check.png, check.svg
* Added "check" icon, used in menu right now to show which item
is selected
ve.ui.Icons-raster.css, ve.ui.Icons-vector.css
* Added check icon
* Removed :before pseudo selectors from most of the icon classes (not need by button tool anymore, makes them more reusable now)
ve.ui.Tool.css
* Adjusted drop down tool styles so menu appears below, instead
of on top, of the label
* Adjusted paragraph font size to better match actual content
* Updated class names to still work with menu widget changes
(items are their own widgets now)
* Updated selectors as per changes in the structure of button tools
ve.ui.Widget.css
* Added styles for buttons and menu items
* Adjusted menu styles
ve.ui.*ButtonTool.js
* Added config options argument passthrough
ve.ui.ButtonTool.js
* Moved var statement to the top inside constructor
* Switched to using "a" tag to get cross-browser :active support
* Added icon to inside of button to make icon styles more reusable
* Removed disabled support (now provided by widget parent class)
ve.ui.FormatDropDownTool.js
* Updated options initialization to construct menu item objects
* Modified handling of items to account for changes in menu and
item classes
* Optimized onUpdateState method a bit, adding early exit to
inner loop
ve.ui.ButtonTool.js, ve.ui.DropdownTool.js, ve.ui.Context.js,
ve.ui.Frame, ve.ui.Tool.js, ve.ui.Widget.js
* Added chain ability to non-getter methods
ve.ui.DropdownTool.js
* Removed items argument to constructor
* Updated code as per changes in menu class
* Fixed inconsistent naming of event handler methods
* Removed item event handling (now handled by items directly)
* Made use of this.$$ to ensure tool works in other frames
ve.ui.Tool.js
* Made tools inherit from widget
* Moved trigger registry event handler to a method
ve.ui.Context.js
* Switched from using menu to contain toolbar to a simple wrapper
ve.ui.js
* Added get$$ method, a convenience function for binding jQuery
to a specific document context
ve.ui.*Widget.js
* Switched to using a config options object instead of individual arguments
* Added options
* Factored out flags and labels into their own classes
* Refactored value setting methods for inputs
ve.ui.MenuWidget.js, ve.ui.MenuItemWidget.js
* Broke items out into their own classes
* Redesigned API
* Updated code that uses these classes
* Added support for keyboard interaction
* Made items flash when selected (delaying the hiding of the menu for 200ms)
ve.ui.LinkTargetInputWidget.js, ve.ui.MWLinkTargetInputWidget
* Refactored annotation setting methods
Change-Id: I7769bd5a5b79f1ab36f258ef9f2be583ca503ce6
2013-02-20 23:25:12 +00:00
|
|
|
* Handle delete and backspace key down events.
|
Make use of new jshint options
* Restricting "camelcase":
No changes, we were passing all of these already
* Explicitly unrestricting "forin" and "plusplus"
These are off by default in node-jshint, but some distro of jshint
and editors that use their own wrapper around jshint instead of
node-jshint (Eclipse?) may have different defaults. Therefor
setting them to false explicitly. This also serves as a reminder
for the future so we'll always know we don't pass that, in case
we would want to change that.
* Fix order ("quotemark" before "regexp")
* Restricting "unused"
We're not passing all of this, which is why I've set it to false
for now. But I did put it in .jshintrc as placeholder.
I've fixed most of them, there's some left where there is no clean
solution.
* While at it fix a few issues:
- Unused variables ($target, $window)
- Bad practices (using jQuery context for find instead of creation)
- Redundant /*global */ comments
- Parameters that are not used and don't have documentation either
- Lines longer than 100 chars @ 4 spaces/tab
* Note:
- ve.ce.Surface.prototype.onChange takes two arguments but never
uses the former. And even the second one can be null/undefined.
Aside from that, the .change() function emits
another event for the transaction already. Looks like this
should be refactored a bit, two more separated events probably
or one that is actually used better.
- Also cleaned up a lot of comments, some of which were missing,
others were incorrect
- Reworked the contentChange event so we are no longer using the
word new as an object key; expanded a complex object into multiple
arguments being passed through the event to make it easier to work
with and document
Change-Id: I8490815a508c6c379d5f9a743bb4aefd14576aa6
2012-08-07 06:02:18 +00:00
|
|
|
*
|
|
|
|
* @method
|
Major UI refactoring and improvements
Objective:
Refactor UI widgets, improve usability and accessibility of menus, general cleanup and style improvements.
Extras:
Fixed documentation in a few other files to make descriptions of jQuery event arguments more consistent, classes inherit correctly, and made use of the @cfg functionality in jsduck.
Changes:
.docs/config.json
* Added window, HTMLDocument, HTMLElement, DocumentFragment and XMLHttpRequest to externals, so jsduck doesn't throw warnings when they are used
demos/ve/index.php, modules/ve/test/index.php, VisualEditor.php
* Moved widgets above tools (since tools use widgets)
demos/ve/index.php
* Refactored widget initialization to use options
* Renamed variables to match widget names
ve.init.mw.ViewPageTarget.css
* Adjusted text sizes to make widgets work normally
* Added margins for buttons in toolbar (since button widgets
don't have any)
* Removed styles for init buttons (button widgets now)
ve.init.mw.ViewPageTarget.js
* Switched to using button widgets (involved moving things around
a bit)
ve.ui.LinkInspector.js, ve.ui.MWLinkInspector.js
* Renamed static property "inputWidget" to
"linkTargetInputWidget" to better reflect the required base class
for the properties value
icons.ai, check.png, check.svg
* Added "check" icon, used in menu right now to show which item
is selected
ve.ui.Icons-raster.css, ve.ui.Icons-vector.css
* Added check icon
* Removed :before pseudo selectors from most of the icon classes (not need by button tool anymore, makes them more reusable now)
ve.ui.Tool.css
* Adjusted drop down tool styles so menu appears below, instead
of on top, of the label
* Adjusted paragraph font size to better match actual content
* Updated class names to still work with menu widget changes
(items are their own widgets now)
* Updated selectors as per changes in the structure of button tools
ve.ui.Widget.css
* Added styles for buttons and menu items
* Adjusted menu styles
ve.ui.*ButtonTool.js
* Added config options argument passthrough
ve.ui.ButtonTool.js
* Moved var statement to the top inside constructor
* Switched to using "a" tag to get cross-browser :active support
* Added icon to inside of button to make icon styles more reusable
* Removed disabled support (now provided by widget parent class)
ve.ui.FormatDropDownTool.js
* Updated options initialization to construct menu item objects
* Modified handling of items to account for changes in menu and
item classes
* Optimized onUpdateState method a bit, adding early exit to
inner loop
ve.ui.ButtonTool.js, ve.ui.DropdownTool.js, ve.ui.Context.js,
ve.ui.Frame, ve.ui.Tool.js, ve.ui.Widget.js
* Added chain ability to non-getter methods
ve.ui.DropdownTool.js
* Removed items argument to constructor
* Updated code as per changes in menu class
* Fixed inconsistent naming of event handler methods
* Removed item event handling (now handled by items directly)
* Made use of this.$$ to ensure tool works in other frames
ve.ui.Tool.js
* Made tools inherit from widget
* Moved trigger registry event handler to a method
ve.ui.Context.js
* Switched from using menu to contain toolbar to a simple wrapper
ve.ui.js
* Added get$$ method, a convenience function for binding jQuery
to a specific document context
ve.ui.*Widget.js
* Switched to using a config options object instead of individual arguments
* Added options
* Factored out flags and labels into their own classes
* Refactored value setting methods for inputs
ve.ui.MenuWidget.js, ve.ui.MenuItemWidget.js
* Broke items out into their own classes
* Redesigned API
* Updated code that uses these classes
* Added support for keyboard interaction
* Made items flash when selected (delaying the hiding of the menu for 200ms)
ve.ui.LinkTargetInputWidget.js, ve.ui.MWLinkTargetInputWidget
* Refactored annotation setting methods
Change-Id: I7769bd5a5b79f1ab36f258ef9f2be583ca503ce6
2013-02-20 23:25:12 +00:00
|
|
|
* @param {jQuery.Event} e Delete key down event
|
2013-01-15 20:15:17 +00:00
|
|
|
* @param {boolean} backspace Key was a backspace
|
Make use of new jshint options
* Restricting "camelcase":
No changes, we were passing all of these already
* Explicitly unrestricting "forin" and "plusplus"
These are off by default in node-jshint, but some distro of jshint
and editors that use their own wrapper around jshint instead of
node-jshint (Eclipse?) may have different defaults. Therefor
setting them to false explicitly. This also serves as a reminder
for the future so we'll always know we don't pass that, in case
we would want to change that.
* Fix order ("quotemark" before "regexp")
* Restricting "unused"
We're not passing all of this, which is why I've set it to false
for now. But I did put it in .jshintrc as placeholder.
I've fixed most of them, there's some left where there is no clean
solution.
* While at it fix a few issues:
- Unused variables ($target, $window)
- Bad practices (using jQuery context for find instead of creation)
- Redundant /*global */ comments
- Parameters that are not used and don't have documentation either
- Lines longer than 100 chars @ 4 spaces/tab
* Note:
- ve.ce.Surface.prototype.onChange takes two arguments but never
uses the former. And even the second one can be null/undefined.
Aside from that, the .change() function emits
another event for the transaction already. Looks like this
should be refactored a bit, two more separated events probably
or one that is actually used better.
- Also cleaned up a lot of comments, some of which were missing,
others were incorrect
- Reworked the contentChange event so we are no longer using the
word new as an object key; expanded a complex object into multiple
arguments being passed through the event to make it easier to work
with and document
Change-Id: I8490815a508c6c379d5f9a743bb4aefd14576aa6
2012-08-07 06:02:18 +00:00
|
|
|
*/
|
2012-08-17 23:28:29 +00:00
|
|
|
ve.ce.Surface.prototype.handleDelete = function ( e, backspace ) {
|
2013-06-13 04:07:20 +00:00
|
|
|
var rangeToRemove = this.model.getSelection(),
|
2013-10-05 10:27:39 +00:00
|
|
|
offset = 0,
|
|
|
|
docLength, tx, startNode, endNode, endNodeData, nodeToDelete;
|
2013-06-13 04:07:20 +00:00
|
|
|
|
|
|
|
if ( rangeToRemove.isCollapsed() ) {
|
|
|
|
// In case when the range is collapsed use the same logic that is used for cursor left and
|
|
|
|
// right movement in order to figure out range to remove.
|
|
|
|
rangeToRemove = this.getDocument().getRelativeRange(
|
|
|
|
rangeToRemove,
|
|
|
|
backspace ? -1 : 1,
|
|
|
|
( e.altKey === true || e.ctrlKey === true ) ? 'word' : 'character',
|
|
|
|
true
|
|
|
|
);
|
2013-10-05 10:27:39 +00:00
|
|
|
offset = rangeToRemove.start;
|
|
|
|
docLength = this.model.getDocument().data.getLength();
|
|
|
|
if ( offset < docLength ) {
|
|
|
|
while ( offset < docLength && this.model.getDocument().data.isCloseElementData( offset ) ) {
|
|
|
|
offset++;
|
|
|
|
}
|
|
|
|
// If the user tries to delete a focusable node from a collapsed selection,
|
|
|
|
// just select the node and cancel the deletion.
|
|
|
|
startNode = this.documentView.getDocumentNode().getNodeFromOffset( offset + 1 );
|
2013-10-11 14:09:00 +00:00
|
|
|
if ( startNode.isFocusable() ) {
|
2013-10-15 18:36:02 +00:00
|
|
|
this.model.setSelection( startNode.getModel().getOuterRange() );
|
2013-10-05 10:27:39 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2013-06-13 04:07:20 +00:00
|
|
|
if ( rangeToRemove.isCollapsed() ) {
|
|
|
|
// For instance beginning or end of the document.
|
|
|
|
return;
|
2012-08-17 23:28:29 +00:00
|
|
|
}
|
2013-06-13 04:07:20 +00:00
|
|
|
}
|
|
|
|
tx = ve.dm.Transaction.newFromRemoval( this.documentView.model, rangeToRemove );
|
|
|
|
this.model.change( tx );
|
|
|
|
rangeToRemove = tx.translateRange( rangeToRemove );
|
|
|
|
if ( !rangeToRemove.isCollapsed() ) {
|
|
|
|
// If after processing removal transaction range is not collapsed it means that not
|
|
|
|
// everything got merged nicely (at this moment transaction processor is capable of merging
|
2013-06-27 18:24:26 +00:00
|
|
|
// nodes of the same type and at the same depth level only), so we process with another
|
2013-09-23 14:20:28 +00:00
|
|
|
// merging that takes remaing data from endNode and inserts it at the end of startNode,
|
|
|
|
// endNode or recrusivly its parent (if have only one child) gets removed.
|
|
|
|
//
|
|
|
|
// If startNode has no content then we just delete that node instead of merging.
|
|
|
|
// This prevents content being inserted into empty structure which, e.g. and empty heading
|
|
|
|
// will be deleted, rather than "converting" the paragraph beneath to a heading.
|
|
|
|
|
2013-06-13 04:07:20 +00:00
|
|
|
endNode = this.documentView.getNodeFromOffset( rangeToRemove.end, false );
|
2013-07-16 11:51:11 +00:00
|
|
|
|
2013-09-23 14:20:28 +00:00
|
|
|
// If endNode is within our rangeToRemove, then we shouldn't delete it
|
2013-07-16 11:51:11 +00:00
|
|
|
if ( endNode.getModel().getRange().start >= rangeToRemove.end ) {
|
2013-09-23 14:20:28 +00:00
|
|
|
startNode = this.documentView.getNodeFromOffset( rangeToRemove.start, false );
|
|
|
|
if ( startNode.getModel().getRange().isCollapsed() ) {
|
|
|
|
// Remove startNode
|
|
|
|
this.model.change( [
|
|
|
|
ve.dm.Transaction.newFromRemoval(
|
|
|
|
this.documentView.model, startNode.getModel().getOuterRange()
|
|
|
|
)
|
|
|
|
] );
|
|
|
|
} else {
|
|
|
|
endNodeData = this.documentView.model.getData( endNode.getModel().getRange() );
|
|
|
|
nodeToDelete = endNode;
|
|
|
|
nodeToDelete.traverseUpstream( function ( node ) {
|
|
|
|
var parent = node.getParent();
|
|
|
|
if ( parent.children.length === 1 ) {
|
|
|
|
nodeToDelete = parent;
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
} );
|
|
|
|
// Move contents of endNode into startNode, and delete nodeToDelete
|
|
|
|
this.model.change( [
|
2013-07-16 11:51:11 +00:00
|
|
|
ve.dm.Transaction.newFromRemoval(
|
|
|
|
this.documentView.model, nodeToDelete.getModel().getOuterRange()
|
|
|
|
),
|
|
|
|
ve.dm.Transaction.newFromInsertion(
|
|
|
|
this.documentView.model, rangeToRemove.start, endNodeData
|
|
|
|
)
|
2013-09-23 14:20:28 +00:00
|
|
|
] );
|
|
|
|
}
|
2013-07-16 11:51:11 +00:00
|
|
|
}
|
2012-03-12 21:50:22 +00:00
|
|
|
}
|
2013-10-15 18:36:02 +00:00
|
|
|
this.model.setSelection( new ve.Range( rangeToRemove.start ) );
|
2012-10-05 21:54:32 +00:00
|
|
|
this.surfaceObserver.clear();
|
2012-02-13 22:45:18 +00:00
|
|
|
};
|
|
|
|
|
Make use of new jshint options
* Restricting "camelcase":
No changes, we were passing all of these already
* Explicitly unrestricting "forin" and "plusplus"
These are off by default in node-jshint, but some distro of jshint
and editors that use their own wrapper around jshint instead of
node-jshint (Eclipse?) may have different defaults. Therefor
setting them to false explicitly. This also serves as a reminder
for the future so we'll always know we don't pass that, in case
we would want to change that.
* Fix order ("quotemark" before "regexp")
* Restricting "unused"
We're not passing all of this, which is why I've set it to false
for now. But I did put it in .jshintrc as placeholder.
I've fixed most of them, there's some left where there is no clean
solution.
* While at it fix a few issues:
- Unused variables ($target, $window)
- Bad practices (using jQuery context for find instead of creation)
- Redundant /*global */ comments
- Parameters that are not used and don't have documentation either
- Lines longer than 100 chars @ 4 spaces/tab
* Note:
- ve.ce.Surface.prototype.onChange takes two arguments but never
uses the former. And even the second one can be null/undefined.
Aside from that, the .change() function emits
another event for the transaction already. Looks like this
should be refactored a bit, two more separated events probably
or one that is actually used better.
- Also cleaned up a lot of comments, some of which were missing,
others were incorrect
- Reworked the contentChange event so we are no longer using the
word new as an object key; expanded a complex object into multiple
arguments being passed through the event to make it easier to work
with and document
Change-Id: I8490815a508c6c379d5f9a743bb4aefd14576aa6
2012-08-07 06:02:18 +00:00
|
|
|
/**
|
2013-01-15 23:38:49 +00:00
|
|
|
* Show selection on a range.
|
Make use of new jshint options
* Restricting "camelcase":
No changes, we were passing all of these already
* Explicitly unrestricting "forin" and "plusplus"
These are off by default in node-jshint, but some distro of jshint
and editors that use their own wrapper around jshint instead of
node-jshint (Eclipse?) may have different defaults. Therefor
setting them to false explicitly. This also serves as a reminder
for the future so we'll always know we don't pass that, in case
we would want to change that.
* Fix order ("quotemark" before "regexp")
* Restricting "unused"
We're not passing all of this, which is why I've set it to false
for now. But I did put it in .jshintrc as placeholder.
I've fixed most of them, there's some left where there is no clean
solution.
* While at it fix a few issues:
- Unused variables ($target, $window)
- Bad practices (using jQuery context for find instead of creation)
- Redundant /*global */ comments
- Parameters that are not used and don't have documentation either
- Lines longer than 100 chars @ 4 spaces/tab
* Note:
- ve.ce.Surface.prototype.onChange takes two arguments but never
uses the former. And even the second one can be null/undefined.
Aside from that, the .change() function emits
another event for the transaction already. Looks like this
should be refactored a bit, two more separated events probably
or one that is actually used better.
- Also cleaned up a lot of comments, some of which were missing,
others were incorrect
- Reworked the contentChange event so we are no longer using the
word new as an object key; expanded a complex object into multiple
arguments being passed through the event to make it easier to work
with and document
Change-Id: I8490815a508c6c379d5f9a743bb4aefd14576aa6
2012-08-07 06:02:18 +00:00
|
|
|
*
|
|
|
|
* @method
|
|
|
|
* @param {ve.Range} range Range to show selection on
|
|
|
|
*/
|
Kranitor #1: On-boarding
'''Kranitor commits''' are commits by Krinkle with his janitor hat on.
Must never contain functional changes mixed with miscellaneous changes.
.gitignore:
* Add .DS_Store to the ignore list so that browsing the directories
on Mac OS X, will not add these files to the list of untracked
files.
* Fix missing newline at end of file
.jshintrc
* raises -> throws
* +module (QUnit.module)
* remove 'Node' (as of node-jshint 1.7.2 this is now part of
'browser:true', as it should be)
Authors:
* Adding myself
MWExtension/VisualEditor.php
* Fix default value of wgVisualEditorParsoidURL to not
point to the experimental instance in WMF Labs.
Issues:
* ve.ce.TextNode:
- Fix TODO: Don't perform a useless clone of an already-jQuerified object.
- Use .html() to set html content instead of encapsulating between
two strings. This is slightly faster but more importantly safer,
and prevents situations where the resulting jQuery collection
actually contains 2 elements instead of 1, thus messing up
what .contents() is iterating over.
* ve.ce.Document.test.js
- Fix: ReferenceError: assert is not defined
* ve.dm.Document.test.js
- Fix: ReferenceError: assert is not defined
* ve.dm.Transaction.test.js
- Fix: ReferenceError: assert is not defined
* ve.dm.TransactionProcessor.test.js
- Fix: ReferenceError: assert is not defined
* ext.visualEditor.viewPageTarget
- Missing dependency on 'mediawiki.Title'
Code conventions / Misc cleanup
* Various JSHint warnings.
* Whitespace
* jQuery(): Use '<tag>' for element creation,
use '<valid><xml/></valid>' for parsing
* Use the default operator instead of ternary when the condition and
first value are the same.
x = foo ? foo : bar; -> x = foo || bar;
Because contrary to some programming language (PHP...), in JS the
default operator does not enforce a boolean result but returns the
original value, hence it being called the 'default' operator, as
opposed to the 'or' operator.
* No need to call addClass() twice, it takes a space-separated list
(jQuery splits by space and adds if needed)
* Use .on( event[, selector], fn ) instead of the deprecated
routers to it such as .bind(), .delegate() and .live().
All these three are now built-in and fully compatible with .on()
* Add 'XXX:' comments for suspicious code that I don't want to change
as part of a clean up commit.
* Remove unused variables (several var x = this; where x was not
used anywhere, possibly from boilerplate copy/paste)
* Follows-up Trevor's commit that converts test suites to the new
QUnit format. Also removed the globals since we no longer use those
any more.
Change-Id: I7e37c9bff812e371c7f65a6fd85d9e2af3e0a22f
2012-07-27 08:43:33 +00:00
|
|
|
ve.ce.Surface.prototype.showSelection = function ( range ) {
|
2012-11-20 01:05:34 +00:00
|
|
|
var start, end,
|
The Great ve.ui.Surface refactor of 2013
Prologue:
Farewell ve.Editor my good chap… Oh, hey there HTML frames - I didn't
see you there! In a world where iframes are outlaws, and symbols like
document and window are global, there were more than a few assumptions
about which document or window was being used. But fear not - for this
commit (probably) tracks them all down, leaving a trail of
iframe-compatible awesomeness in its wake. With the great ve.ui.Surface
now able to be used inside of iframes, let the reference editing
commence. But there, lurking in the darkness is a DM issue so fierce it
may take Roan and/or Ed up to 3 whole hours to sort it out.
Note to Roan and/or Ed:
Editing references seems to work fine, but when saving the page there
are "no changes" which is a reasonable indication to the contrary.
Objectives:
* Make it possible to have multiple surfaces be instantiated, get along
nicely, and be embedded inside of iframes if needed.
* Make reference content editable within a dialog
Approach:
* Move what's left of ve.Editor to ve.ui.Surface and essentially
obliterate all use of it
* Make even more stuff inherit from ve.Element (long live this.$$)
* Use the correct document or window anywhere it was being assumed to be
the top level one
* Resolve stacking order issues by removing the excessive use of z-index
and introducing global and local overlay elements for each editor
* Add a surface to the reference dialog, load up the reference contents
and save them back on apply
* Actually destroy what we create in ce and ui surfaces
* Add recursive frame offset calculation method to ve.Element
* Moved ve.ce.Surface's getSelectionRect method to the prototype
Bonus:
* Move ve.ce.DocumentNode.css contents to ve.ce.Node.css (not sure why it
was separate in the first place, but I'm likely the one to blame)
* Fix blatant lies in documentation
* Whitespace cleanup here and there
* Get rid of ve.ui.Window overlays - not used or needed
Change-Id: Iede83e7d24f7cb249b6ba3dc45d770445b862e08
2013-05-20 22:45:50 +00:00
|
|
|
rangySel = rangy.getSelection( this.$document[0] ),
|
|
|
|
rangyRange = rangy.createRange( this.$document[0] );
|
2012-06-20 01:20:28 +00:00
|
|
|
|
2013-06-05 20:59:19 +00:00
|
|
|
range = new ve.Range(
|
|
|
|
this.getNearestCorrectOffset( range.from, -1 ),
|
|
|
|
this.getNearestCorrectOffset( range.to, 1 )
|
|
|
|
);
|
2012-11-26 23:01:35 +00:00
|
|
|
|
2013-01-16 20:22:07 +00:00
|
|
|
if ( !range.isCollapsed() ) {
|
2013-03-26 06:10:17 +00:00
|
|
|
start = this.documentView.getNodeAndOffset( range.start );
|
|
|
|
end = this.documentView.getNodeAndOffset( range.end );
|
2012-06-20 01:20:28 +00:00
|
|
|
rangyRange.setStart( start.node, start.offset );
|
|
|
|
rangyRange.setEnd( end.node, end.offset );
|
|
|
|
rangySel.removeAllRanges();
|
|
|
|
rangySel.addRange( rangyRange, range.start !== range.from );
|
|
|
|
} else {
|
2013-03-26 06:10:17 +00:00
|
|
|
start = this.documentView.getNodeAndOffset( range.start );
|
2012-06-20 01:20:28 +00:00
|
|
|
rangyRange.setStart( start.node, start.offset );
|
|
|
|
rangySel.setSingleRange( rangyRange );
|
|
|
|
}
|
2012-03-02 02:07:55 +00:00
|
|
|
};
|
|
|
|
|
2013-01-18 01:02:02 +00:00
|
|
|
/**
|
|
|
|
* Append passed phantoms to phantoms container after emptying it first.
|
|
|
|
*
|
|
|
|
* @method
|
|
|
|
* @param {jQuery} $phantoms Phantoms to append
|
|
|
|
*/
|
2013-05-06 11:34:32 +00:00
|
|
|
ve.ce.Surface.prototype.replacePhantoms = function ( $phantoms ) {
|
2013-01-18 01:02:02 +00:00
|
|
|
this.$phantoms.empty().append( $phantoms );
|
|
|
|
};
|
|
|
|
|
2013-06-05 20:59:19 +00:00
|
|
|
/**
|
|
|
|
* Append passed highlights to highlight container after emptying it first.
|
|
|
|
*
|
|
|
|
* @method
|
|
|
|
* @param {jQuery} $highlights Highlights to append
|
|
|
|
*/
|
|
|
|
ve.ce.Surface.prototype.replaceHighlight = function ( $highlights ) {
|
|
|
|
this.$highlights.empty().append( $highlights );
|
|
|
|
};
|
|
|
|
|
2013-01-16 21:51:05 +00:00
|
|
|
/*! Helpers */
|
|
|
|
|
Make use of new jshint options
* Restricting "camelcase":
No changes, we were passing all of these already
* Explicitly unrestricting "forin" and "plusplus"
These are off by default in node-jshint, but some distro of jshint
and editors that use their own wrapper around jshint instead of
node-jshint (Eclipse?) may have different defaults. Therefor
setting them to false explicitly. This also serves as a reminder
for the future so we'll always know we don't pass that, in case
we would want to change that.
* Fix order ("quotemark" before "regexp")
* Restricting "unused"
We're not passing all of this, which is why I've set it to false
for now. But I did put it in .jshintrc as placeholder.
I've fixed most of them, there's some left where there is no clean
solution.
* While at it fix a few issues:
- Unused variables ($target, $window)
- Bad practices (using jQuery context for find instead of creation)
- Redundant /*global */ comments
- Parameters that are not used and don't have documentation either
- Lines longer than 100 chars @ 4 spaces/tab
* Note:
- ve.ce.Surface.prototype.onChange takes two arguments but never
uses the former. And even the second one can be null/undefined.
Aside from that, the .change() function emits
another event for the transaction already. Looks like this
should be refactored a bit, two more separated events probably
or one that is actually used better.
- Also cleaned up a lot of comments, some of which were missing,
others were incorrect
- Reworked the contentChange event so we are no longer using the
word new as an object key; expanded a complex object into multiple
arguments being passed through the event to make it easier to work
with and document
Change-Id: I8490815a508c6c379d5f9a743bb4aefd14576aa6
2012-08-07 06:02:18 +00:00
|
|
|
/**
|
2013-01-15 23:38:49 +00:00
|
|
|
* Get the nearest offset that a cursor can be placed at.
|
Make use of new jshint options
* Restricting "camelcase":
No changes, we were passing all of these already
* Explicitly unrestricting "forin" and "plusplus"
These are off by default in node-jshint, but some distro of jshint
and editors that use their own wrapper around jshint instead of
node-jshint (Eclipse?) may have different defaults. Therefor
setting them to false explicitly. This also serves as a reminder
for the future so we'll always know we don't pass that, in case
we would want to change that.
* Fix order ("quotemark" before "regexp")
* Restricting "unused"
We're not passing all of this, which is why I've set it to false
for now. But I did put it in .jshintrc as placeholder.
I've fixed most of them, there's some left where there is no clean
solution.
* While at it fix a few issues:
- Unused variables ($target, $window)
- Bad practices (using jQuery context for find instead of creation)
- Redundant /*global */ comments
- Parameters that are not used and don't have documentation either
- Lines longer than 100 chars @ 4 spaces/tab
* Note:
- ve.ce.Surface.prototype.onChange takes two arguments but never
uses the former. And even the second one can be null/undefined.
Aside from that, the .change() function emits
another event for the transaction already. Looks like this
should be refactored a bit, two more separated events probably
or one that is actually used better.
- Also cleaned up a lot of comments, some of which were missing,
others were incorrect
- Reworked the contentChange event so we are no longer using the
word new as an object key; expanded a complex object into multiple
arguments being passed through the event to make it easier to work
with and document
Change-Id: I8490815a508c6c379d5f9a743bb4aefd14576aa6
2012-08-07 06:02:18 +00:00
|
|
|
*
|
|
|
|
* TODO: Find a better name and a better place for this method
|
|
|
|
*
|
|
|
|
* @method
|
JSDuck: Generated code documentation!
See CODING.md for how to run it.
Mistakes fixed:
* Warning: Unknown type function
-> Function
* Warning: Unknown type DOMElement
-> HTMLElement
* Warning: Unknown type DOM Node
-> HTMLElement
* Warning: Unknown type Integer
-> Mixed
* Warning: Unknown type Command
-> ve.Command
* Warning: Unknown type any
-> number
* Warning: Unknown type ve.Transaction
-> ve.dm.Transaction
* Warning: Unknown type ve.dm.AnnotationSet
-> ve.AnnotationSet
* Warning: Unknown type false
-> boolean
* Warning: Unknown type ve.dm.AlienNode
ve.dm doesn't have a generic AlienNode like ve.ce
-> Unknown type ve.dm.AlienInlineNode|ve.dm.AlienBlockNode
* Warning: Unknown type ve.ve.Surface
-> ve.ce.Surface
* ve.example.lookupNode:
-> Last @param should be @return
* ve.dm.Transaction.prototype.pushReplace:
-> @param {Array] should be @param {Array}
* Warning: ve.BranchNode.js:27: {@link ve.Node#hasChildren} links to non-existing member
-> (removed)
* Warning: ve.LeafNode.js:21: {@link ve.Node#hasChildren} links to non-existing member
-> (removed)
Differences fixed:
* Variadic arguments are like @param {Type...} [name]
instead of @param {Type} [name...]
* Convert all file headers from /** to /*! because JSDuck tries
to parse all /** blocks and fails to parse with all sorts of
errors for "Global property", "Unnamed property", and
"Duplicate property".
Find: \/\*\*([^@]+)(@copyright)
Replace: /*!$1$2
* Indented blocks are considered code examples.
A few methods had documentation with numbered lists that were
indented, which have now been updated to not be intended.
* The free-form text descriptions are parsed with Markdown,
which requires lists to be separated from paragraphs by an
empty line.
And we should use `backticks` instead of {braces} for inline
code in text paragraphs.
* Doc blocks for classes and their constructor have to be
in the correct order (@constructor, @param, @return must be
before @class, @abstract, @extends etc.)
* `@extends Class` must not have Class {wrapped}
* @throws must start with a {Type}
* @example means something else. It is used for an inline demo
iframe, not code block. For that simply indent with spaces.
* @member means something else.
Non-function properties are marked with @property, not @member.
* To create a link to a class or member, in most cases the name
is enough to create a link. E.g. Foo, Foo.bar, Foo.bar#quux,
where a hash stands for "instance member", so Foo.bar#quux,
links to Foo.bar.prototype.quux (the is not supported, as
"prototype" is considered an implementation detail, it only
indexes class name and method name).
If the magic linker doesn't work for some case, the
verbose syntax is {@link #target label}.
* @property can't have sub-properties (nested @param and @return
values are supported, only @static @property can't be nested).
We only have one case of this, which can be worked around by
moving those in a new virtual class. The code is unaltered
(only moved down so that it isn't with the scope of the main
@class block). ve.dm.TransactionProcessor.processors.
New:
* @mixins: Classes mixed into the current class.
* @event: Events that can be emitted by a class. These are also
inherited by subclasses. (+ @param, @return and @preventable).
So ve.Node#event-attach is inherited to ve.dm.BreakNode,
just like @method is.
* @singleton: Plain objects such as ve, ve.dm, ve.ce were missing
documentation causing a tree error. Documented those as a
JSDuck singleton, which they but just weren't documented yet.
NB: Members of @singleton don't need @static (if present,
triggers a compiler warning).
* @chainable: Shorthand for "@return this". We were using
"@return {classname}" which is ambiguous (returns the same
instance or another instance?), @chainable is specifically
for "@return this". Creates proper labels in the generated
HTML pages.
Removed:
* @mixin: (not to be confused with @mixins). Not supported by
JSDuck. Every class is standalone anyway. Where needed marked
them @class + @abstract instead.
Change-Id: I6a7c9e8ee8f995731bc205d666167874eb2ebe23
2013-01-04 08:54:17 +00:00
|
|
|
* @param {number} offset Offset to start looking at
|
|
|
|
* @param {number} [direction=-1] Direction to look in, +1 or -1
|
Make use of new jshint options
* Restricting "camelcase":
No changes, we were passing all of these already
* Explicitly unrestricting "forin" and "plusplus"
These are off by default in node-jshint, but some distro of jshint
and editors that use their own wrapper around jshint instead of
node-jshint (Eclipse?) may have different defaults. Therefor
setting them to false explicitly. This also serves as a reminder
for the future so we'll always know we don't pass that, in case
we would want to change that.
* Fix order ("quotemark" before "regexp")
* Restricting "unused"
We're not passing all of this, which is why I've set it to false
for now. But I did put it in .jshintrc as placeholder.
I've fixed most of them, there's some left where there is no clean
solution.
* While at it fix a few issues:
- Unused variables ($target, $window)
- Bad practices (using jQuery context for find instead of creation)
- Redundant /*global */ comments
- Parameters that are not used and don't have documentation either
- Lines longer than 100 chars @ 4 spaces/tab
* Note:
- ve.ce.Surface.prototype.onChange takes two arguments but never
uses the former. And even the second one can be null/undefined.
Aside from that, the .change() function emits
another event for the transaction already. Looks like this
should be refactored a bit, two more separated events probably
or one that is actually used better.
- Also cleaned up a lot of comments, some of which were missing,
others were incorrect
- Reworked the contentChange event so we are no longer using the
word new as an object key; expanded a complex object into multiple
arguments being passed through the event to make it easier to work
with and document
Change-Id: I8490815a508c6c379d5f9a743bb4aefd14576aa6
2012-08-07 06:02:18 +00:00
|
|
|
*/
|
Kranitor #1: On-boarding
'''Kranitor commits''' are commits by Krinkle with his janitor hat on.
Must never contain functional changes mixed with miscellaneous changes.
.gitignore:
* Add .DS_Store to the ignore list so that browsing the directories
on Mac OS X, will not add these files to the list of untracked
files.
* Fix missing newline at end of file
.jshintrc
* raises -> throws
* +module (QUnit.module)
* remove 'Node' (as of node-jshint 1.7.2 this is now part of
'browser:true', as it should be)
Authors:
* Adding myself
MWExtension/VisualEditor.php
* Fix default value of wgVisualEditorParsoidURL to not
point to the experimental instance in WMF Labs.
Issues:
* ve.ce.TextNode:
- Fix TODO: Don't perform a useless clone of an already-jQuerified object.
- Use .html() to set html content instead of encapsulating between
two strings. This is slightly faster but more importantly safer,
and prevents situations where the resulting jQuery collection
actually contains 2 elements instead of 1, thus messing up
what .contents() is iterating over.
* ve.ce.Document.test.js
- Fix: ReferenceError: assert is not defined
* ve.dm.Document.test.js
- Fix: ReferenceError: assert is not defined
* ve.dm.Transaction.test.js
- Fix: ReferenceError: assert is not defined
* ve.dm.TransactionProcessor.test.js
- Fix: ReferenceError: assert is not defined
* ext.visualEditor.viewPageTarget
- Missing dependency on 'mediawiki.Title'
Code conventions / Misc cleanup
* Various JSHint warnings.
* Whitespace
* jQuery(): Use '<tag>' for element creation,
use '<valid><xml/></valid>' for parsing
* Use the default operator instead of ternary when the condition and
first value are the same.
x = foo ? foo : bar; -> x = foo || bar;
Because contrary to some programming language (PHP...), in JS the
default operator does not enforce a boolean result but returns the
original value, hence it being called the 'default' operator, as
opposed to the 'or' operator.
* No need to call addClass() twice, it takes a space-separated list
(jQuery splits by space and adds if needed)
* Use .on( event[, selector], fn ) instead of the deprecated
routers to it such as .bind(), .delegate() and .live().
All these three are now built-in and fully compatible with .on()
* Add 'XXX:' comments for suspicious code that I don't want to change
as part of a clean up commit.
* Remove unused variables (several var x = this; where x was not
used anywhere, possibly from boilerplate copy/paste)
* Follows-up Trevor's commit that converts test suites to the new
QUnit format. Also removed the globals since we no longer use those
any more.
Change-Id: I7e37c9bff812e371c7f65a6fd85d9e2af3e0a22f
2012-07-27 08:43:33 +00:00
|
|
|
ve.ce.Surface.prototype.getNearestCorrectOffset = function ( offset, direction ) {
|
Remainder JSHint fixes on modules/ve/*
[jshint]
ce/ve.ce.Surface.js: line 670, col 9, Too many var statements.
ce/ve.ce.Surface.js: line 695, col 6, Missing semicolon.
ce/ve.ce.Surface.js: line 726, col 22, Expected '===' and instead saw '=='.
ce/ve.ce.Surface.js: line 726, col 41, Expected '===' and instead saw '=='.
ce/ve.ce.Surface.js: line 733, col 13, Too many var statements.
ce/ve.ce.Surface.js: line 734, col 24, Expected '===' and instead saw '=='.
ce/ve.ce.Surface.js: line 1013, col 13, Too many var statements.
ce/ve.ce.Surface.js: line 1019, col 17, Too many var statements.
ce/ve.ce.Surface.js: line 1023, col 18, Too many ar statements.
ce/ve.ce.Surface.js: line 1027, col 13, Too many var statements.
dm/annotations/ve.dm.LinkAnnotation.js: line 70, col 52, Insecure '.'.
dm/ve.dm.Converter.js: line 383, col 29, Empty block.
dm/ve.dm.Converter.js: line 423, col 33, Empty block.
Commands:
* jshint .
* ack '(if|else|function|switch|for|while)\('
* Sublime Text 2:
Find(*): (if|else|function|switch|for|while)\(
Replace: $1 (
* ack ' ' -Q # double spaces, except in certain comments
Change-Id: I8e34bf2924bc8688fdf8acef08bbc4f6707e93be
2012-09-02 21:45:01 +00:00
|
|
|
var contentOffset, structuralOffset;
|
2012-04-06 15:10:30 +00:00
|
|
|
|
2012-11-20 01:05:34 +00:00
|
|
|
direction = direction > 0 ? 1 : -1;
|
2012-06-20 01:20:28 +00:00
|
|
|
if (
|
2013-03-20 22:35:05 +00:00
|
|
|
this.documentView.model.data.isContentOffset( offset ) ||
|
2012-06-20 01:20:28 +00:00
|
|
|
this.hasSlugAtOffset( offset )
|
|
|
|
) {
|
|
|
|
return offset;
|
2012-03-02 02:07:55 +00:00
|
|
|
}
|
2012-06-20 01:20:28 +00:00
|
|
|
|
2013-03-20 22:35:05 +00:00
|
|
|
contentOffset = this.documentView.model.data.getNearestContentOffset( offset, direction );
|
2013-01-15 23:38:49 +00:00
|
|
|
structuralOffset =
|
2013-03-20 22:35:05 +00:00
|
|
|
this.documentView.model.data.getNearestStructuralOffset( offset, direction, true );
|
2012-06-20 01:20:28 +00:00
|
|
|
|
|
|
|
if ( !this.hasSlugAtOffset( structuralOffset ) ) {
|
|
|
|
return contentOffset;
|
2012-03-02 00:10:08 +00:00
|
|
|
}
|
2012-06-20 01:20:28 +00:00
|
|
|
|
|
|
|
if ( direction === 1 ) {
|
|
|
|
if ( contentOffset < offset ) {
|
|
|
|
return structuralOffset;
|
|
|
|
} else {
|
|
|
|
return Math.min( contentOffset, structuralOffset );
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if ( contentOffset > offset ) {
|
|
|
|
return structuralOffset;
|
|
|
|
} else {
|
|
|
|
return Math.max( contentOffset, structuralOffset );
|
|
|
|
}
|
2012-03-02 01:35:34 +00:00
|
|
|
}
|
2012-03-02 00:10:08 +00:00
|
|
|
};
|
|
|
|
|
Make use of new jshint options
* Restricting "camelcase":
No changes, we were passing all of these already
* Explicitly unrestricting "forin" and "plusplus"
These are off by default in node-jshint, but some distro of jshint
and editors that use their own wrapper around jshint instead of
node-jshint (Eclipse?) may have different defaults. Therefor
setting them to false explicitly. This also serves as a reminder
for the future so we'll always know we don't pass that, in case
we would want to change that.
* Fix order ("quotemark" before "regexp")
* Restricting "unused"
We're not passing all of this, which is why I've set it to false
for now. But I did put it in .jshintrc as placeholder.
I've fixed most of them, there's some left where there is no clean
solution.
* While at it fix a few issues:
- Unused variables ($target, $window)
- Bad practices (using jQuery context for find instead of creation)
- Redundant /*global */ comments
- Parameters that are not used and don't have documentation either
- Lines longer than 100 chars @ 4 spaces/tab
* Note:
- ve.ce.Surface.prototype.onChange takes two arguments but never
uses the former. And even the second one can be null/undefined.
Aside from that, the .change() function emits
another event for the transaction already. Looks like this
should be refactored a bit, two more separated events probably
or one that is actually used better.
- Also cleaned up a lot of comments, some of which were missing,
others were incorrect
- Reworked the contentChange event so we are no longer using the
word new as an object key; expanded a complex object into multiple
arguments being passed through the event to make it easier to work
with and document
Change-Id: I8490815a508c6c379d5f9a743bb4aefd14576aa6
2012-08-07 06:02:18 +00:00
|
|
|
/**
|
2013-01-15 23:38:49 +00:00
|
|
|
* Check if an offset is inside a slug.
|
Make use of new jshint options
* Restricting "camelcase":
No changes, we were passing all of these already
* Explicitly unrestricting "forin" and "plusplus"
These are off by default in node-jshint, but some distro of jshint
and editors that use their own wrapper around jshint instead of
node-jshint (Eclipse?) may have different defaults. Therefor
setting them to false explicitly. This also serves as a reminder
for the future so we'll always know we don't pass that, in case
we would want to change that.
* Fix order ("quotemark" before "regexp")
* Restricting "unused"
We're not passing all of this, which is why I've set it to false
for now. But I did put it in .jshintrc as placeholder.
I've fixed most of them, there's some left where there is no clean
solution.
* While at it fix a few issues:
- Unused variables ($target, $window)
- Bad practices (using jQuery context for find instead of creation)
- Redundant /*global */ comments
- Parameters that are not used and don't have documentation either
- Lines longer than 100 chars @ 4 spaces/tab
* Note:
- ve.ce.Surface.prototype.onChange takes two arguments but never
uses the former. And even the second one can be null/undefined.
Aside from that, the .change() function emits
another event for the transaction already. Looks like this
should be refactored a bit, two more separated events probably
or one that is actually used better.
- Also cleaned up a lot of comments, some of which were missing,
others were incorrect
- Reworked the contentChange event so we are no longer using the
word new as an object key; expanded a complex object into multiple
arguments being passed through the event to make it easier to work
with and document
Change-Id: I8490815a508c6c379d5f9a743bb4aefd14576aa6
2012-08-07 06:02:18 +00:00
|
|
|
*
|
|
|
|
* TODO: Find a better name and a better place for this method - probably in a document view?
|
|
|
|
*
|
|
|
|
* @method
|
JSDuck: Generated code documentation!
See CODING.md for how to run it.
Mistakes fixed:
* Warning: Unknown type function
-> Function
* Warning: Unknown type DOMElement
-> HTMLElement
* Warning: Unknown type DOM Node
-> HTMLElement
* Warning: Unknown type Integer
-> Mixed
* Warning: Unknown type Command
-> ve.Command
* Warning: Unknown type any
-> number
* Warning: Unknown type ve.Transaction
-> ve.dm.Transaction
* Warning: Unknown type ve.dm.AnnotationSet
-> ve.AnnotationSet
* Warning: Unknown type false
-> boolean
* Warning: Unknown type ve.dm.AlienNode
ve.dm doesn't have a generic AlienNode like ve.ce
-> Unknown type ve.dm.AlienInlineNode|ve.dm.AlienBlockNode
* Warning: Unknown type ve.ve.Surface
-> ve.ce.Surface
* ve.example.lookupNode:
-> Last @param should be @return
* ve.dm.Transaction.prototype.pushReplace:
-> @param {Array] should be @param {Array}
* Warning: ve.BranchNode.js:27: {@link ve.Node#hasChildren} links to non-existing member
-> (removed)
* Warning: ve.LeafNode.js:21: {@link ve.Node#hasChildren} links to non-existing member
-> (removed)
Differences fixed:
* Variadic arguments are like @param {Type...} [name]
instead of @param {Type} [name...]
* Convert all file headers from /** to /*! because JSDuck tries
to parse all /** blocks and fails to parse with all sorts of
errors for "Global property", "Unnamed property", and
"Duplicate property".
Find: \/\*\*([^@]+)(@copyright)
Replace: /*!$1$2
* Indented blocks are considered code examples.
A few methods had documentation with numbered lists that were
indented, which have now been updated to not be intended.
* The free-form text descriptions are parsed with Markdown,
which requires lists to be separated from paragraphs by an
empty line.
And we should use `backticks` instead of {braces} for inline
code in text paragraphs.
* Doc blocks for classes and their constructor have to be
in the correct order (@constructor, @param, @return must be
before @class, @abstract, @extends etc.)
* `@extends Class` must not have Class {wrapped}
* @throws must start with a {Type}
* @example means something else. It is used for an inline demo
iframe, not code block. For that simply indent with spaces.
* @member means something else.
Non-function properties are marked with @property, not @member.
* To create a link to a class or member, in most cases the name
is enough to create a link. E.g. Foo, Foo.bar, Foo.bar#quux,
where a hash stands for "instance member", so Foo.bar#quux,
links to Foo.bar.prototype.quux (the is not supported, as
"prototype" is considered an implementation detail, it only
indexes class name and method name).
If the magic linker doesn't work for some case, the
verbose syntax is {@link #target label}.
* @property can't have sub-properties (nested @param and @return
values are supported, only @static @property can't be nested).
We only have one case of this, which can be worked around by
moving those in a new virtual class. The code is unaltered
(only moved down so that it isn't with the scope of the main
@class block). ve.dm.TransactionProcessor.processors.
New:
* @mixins: Classes mixed into the current class.
* @event: Events that can be emitted by a class. These are also
inherited by subclasses. (+ @param, @return and @preventable).
So ve.Node#event-attach is inherited to ve.dm.BreakNode,
just like @method is.
* @singleton: Plain objects such as ve, ve.dm, ve.ce were missing
documentation causing a tree error. Documented those as a
JSDuck singleton, which they but just weren't documented yet.
NB: Members of @singleton don't need @static (if present,
triggers a compiler warning).
* @chainable: Shorthand for "@return this". We were using
"@return {classname}" which is ambiguous (returns the same
instance or another instance?), @chainable is specifically
for "@return this". Creates proper labels in the generated
HTML pages.
Removed:
* @mixin: (not to be confused with @mixins). Not supported by
JSDuck. Every class is standalone anyway. Where needed marked
them @class + @abstract instead.
Change-Id: I6a7c9e8ee8f995731bc205d666167874eb2ebe23
2013-01-04 08:54:17 +00:00
|
|
|
* @param {number} offset Offset to check for a slug at
|
|
|
|
* @returns {boolean} A slug exists at the given offset
|
Make use of new jshint options
* Restricting "camelcase":
No changes, we were passing all of these already
* Explicitly unrestricting "forin" and "plusplus"
These are off by default in node-jshint, but some distro of jshint
and editors that use their own wrapper around jshint instead of
node-jshint (Eclipse?) may have different defaults. Therefor
setting them to false explicitly. This also serves as a reminder
for the future so we'll always know we don't pass that, in case
we would want to change that.
* Fix order ("quotemark" before "regexp")
* Restricting "unused"
We're not passing all of this, which is why I've set it to false
for now. But I did put it in .jshintrc as placeholder.
I've fixed most of them, there's some left where there is no clean
solution.
* While at it fix a few issues:
- Unused variables ($target, $window)
- Bad practices (using jQuery context for find instead of creation)
- Redundant /*global */ comments
- Parameters that are not used and don't have documentation either
- Lines longer than 100 chars @ 4 spaces/tab
* Note:
- ve.ce.Surface.prototype.onChange takes two arguments but never
uses the former. And even the second one can be null/undefined.
Aside from that, the .change() function emits
another event for the transaction already. Looks like this
should be refactored a bit, two more separated events probably
or one that is actually used better.
- Also cleaned up a lot of comments, some of which were missing,
others were incorrect
- Reworked the contentChange event so we are no longer using the
word new as an object key; expanded a complex object into multiple
arguments being passed through the event to make it easier to work
with and document
Change-Id: I8490815a508c6c379d5f9a743bb4aefd14576aa6
2012-08-07 06:02:18 +00:00
|
|
|
*/
|
Kranitor #1: On-boarding
'''Kranitor commits''' are commits by Krinkle with his janitor hat on.
Must never contain functional changes mixed with miscellaneous changes.
.gitignore:
* Add .DS_Store to the ignore list so that browsing the directories
on Mac OS X, will not add these files to the list of untracked
files.
* Fix missing newline at end of file
.jshintrc
* raises -> throws
* +module (QUnit.module)
* remove 'Node' (as of node-jshint 1.7.2 this is now part of
'browser:true', as it should be)
Authors:
* Adding myself
MWExtension/VisualEditor.php
* Fix default value of wgVisualEditorParsoidURL to not
point to the experimental instance in WMF Labs.
Issues:
* ve.ce.TextNode:
- Fix TODO: Don't perform a useless clone of an already-jQuerified object.
- Use .html() to set html content instead of encapsulating between
two strings. This is slightly faster but more importantly safer,
and prevents situations where the resulting jQuery collection
actually contains 2 elements instead of 1, thus messing up
what .contents() is iterating over.
* ve.ce.Document.test.js
- Fix: ReferenceError: assert is not defined
* ve.dm.Document.test.js
- Fix: ReferenceError: assert is not defined
* ve.dm.Transaction.test.js
- Fix: ReferenceError: assert is not defined
* ve.dm.TransactionProcessor.test.js
- Fix: ReferenceError: assert is not defined
* ext.visualEditor.viewPageTarget
- Missing dependency on 'mediawiki.Title'
Code conventions / Misc cleanup
* Various JSHint warnings.
* Whitespace
* jQuery(): Use '<tag>' for element creation,
use '<valid><xml/></valid>' for parsing
* Use the default operator instead of ternary when the condition and
first value are the same.
x = foo ? foo : bar; -> x = foo || bar;
Because contrary to some programming language (PHP...), in JS the
default operator does not enforce a boolean result but returns the
original value, hence it being called the 'default' operator, as
opposed to the 'or' operator.
* No need to call addClass() twice, it takes a space-separated list
(jQuery splits by space and adds if needed)
* Use .on( event[, selector], fn ) instead of the deprecated
routers to it such as .bind(), .delegate() and .live().
All these three are now built-in and fully compatible with .on()
* Add 'XXX:' comments for suspicious code that I don't want to change
as part of a clean up commit.
* Remove unused variables (several var x = this; where x was not
used anywhere, possibly from boilerplate copy/paste)
* Follows-up Trevor's commit that converts test suites to the new
QUnit format. Also removed the globals since we no longer use those
any more.
Change-Id: I7e37c9bff812e371c7f65a6fd85d9e2af3e0a22f
2012-07-27 08:43:33 +00:00
|
|
|
ve.ce.Surface.prototype.hasSlugAtOffset = function ( offset ) {
|
2012-11-28 01:29:09 +00:00
|
|
|
return !!this.documentView.getSlugAtOffset( offset );
|
2012-06-20 01:20:28 +00:00
|
|
|
};
|
|
|
|
|
Make use of new jshint options
* Restricting "camelcase":
No changes, we were passing all of these already
* Explicitly unrestricting "forin" and "plusplus"
These are off by default in node-jshint, but some distro of jshint
and editors that use their own wrapper around jshint instead of
node-jshint (Eclipse?) may have different defaults. Therefor
setting them to false explicitly. This also serves as a reminder
for the future so we'll always know we don't pass that, in case
we would want to change that.
* Fix order ("quotemark" before "regexp")
* Restricting "unused"
We're not passing all of this, which is why I've set it to false
for now. But I did put it in .jshintrc as placeholder.
I've fixed most of them, there's some left where there is no clean
solution.
* While at it fix a few issues:
- Unused variables ($target, $window)
- Bad practices (using jQuery context for find instead of creation)
- Redundant /*global */ comments
- Parameters that are not used and don't have documentation either
- Lines longer than 100 chars @ 4 spaces/tab
* Note:
- ve.ce.Surface.prototype.onChange takes two arguments but never
uses the former. And even the second one can be null/undefined.
Aside from that, the .change() function emits
another event for the transaction already. Looks like this
should be refactored a bit, two more separated events probably
or one that is actually used better.
- Also cleaned up a lot of comments, some of which were missing,
others were incorrect
- Reworked the contentChange event so we are no longer using the
word new as an object key; expanded a complex object into multiple
arguments being passed through the event to make it easier to work
with and document
Change-Id: I8490815a508c6c379d5f9a743bb4aefd14576aa6
2012-08-07 06:02:18 +00:00
|
|
|
/**
|
2013-01-16 21:51:05 +00:00
|
|
|
* Get the number of consecutive clicks the user has performed.
|
|
|
|
*
|
|
|
|
* This is required for supporting double, tripple, etc. clicking across all browsers.
|
Make use of new jshint options
* Restricting "camelcase":
No changes, we were passing all of these already
* Explicitly unrestricting "forin" and "plusplus"
These are off by default in node-jshint, but some distro of jshint
and editors that use their own wrapper around jshint instead of
node-jshint (Eclipse?) may have different defaults. Therefor
setting them to false explicitly. This also serves as a reminder
for the future so we'll always know we don't pass that, in case
we would want to change that.
* Fix order ("quotemark" before "regexp")
* Restricting "unused"
We're not passing all of this, which is why I've set it to false
for now. But I did put it in .jshintrc as placeholder.
I've fixed most of them, there's some left where there is no clean
solution.
* While at it fix a few issues:
- Unused variables ($target, $window)
- Bad practices (using jQuery context for find instead of creation)
- Redundant /*global */ comments
- Parameters that are not used and don't have documentation either
- Lines longer than 100 chars @ 4 spaces/tab
* Note:
- ve.ce.Surface.prototype.onChange takes two arguments but never
uses the former. And even the second one can be null/undefined.
Aside from that, the .change() function emits
another event for the transaction already. Looks like this
should be refactored a bit, two more separated events probably
or one that is actually used better.
- Also cleaned up a lot of comments, some of which were missing,
others were incorrect
- Reworked the contentChange event so we are no longer using the
word new as an object key; expanded a complex object into multiple
arguments being passed through the event to make it easier to work
with and document
Change-Id: I8490815a508c6c379d5f9a743bb4aefd14576aa6
2012-08-07 06:02:18 +00:00
|
|
|
*
|
|
|
|
* @method
|
2013-03-20 07:09:43 +00:00
|
|
|
* @param {Event} e Native event object
|
|
|
|
* @returns {number} Number of clicks detected
|
Make use of new jshint options
* Restricting "camelcase":
No changes, we were passing all of these already
* Explicitly unrestricting "forin" and "plusplus"
These are off by default in node-jshint, but some distro of jshint
and editors that use their own wrapper around jshint instead of
node-jshint (Eclipse?) may have different defaults. Therefor
setting them to false explicitly. This also serves as a reminder
for the future so we'll always know we don't pass that, in case
we would want to change that.
* Fix order ("quotemark" before "regexp")
* Restricting "unused"
We're not passing all of this, which is why I've set it to false
for now. But I did put it in .jshintrc as placeholder.
I've fixed most of them, there's some left where there is no clean
solution.
* While at it fix a few issues:
- Unused variables ($target, $window)
- Bad practices (using jQuery context for find instead of creation)
- Redundant /*global */ comments
- Parameters that are not used and don't have documentation either
- Lines longer than 100 chars @ 4 spaces/tab
* Note:
- ve.ce.Surface.prototype.onChange takes two arguments but never
uses the former. And even the second one can be null/undefined.
Aside from that, the .change() function emits
another event for the transaction already. Looks like this
should be refactored a bit, two more separated events probably
or one that is actually used better.
- Also cleaned up a lot of comments, some of which were missing,
others were incorrect
- Reworked the contentChange event so we are no longer using the
word new as an object key; expanded a complex object into multiple
arguments being passed through the event to make it easier to work
with and document
Change-Id: I8490815a508c6c379d5f9a743bb4aefd14576aa6
2012-08-07 06:02:18 +00:00
|
|
|
*/
|
2013-01-16 21:51:05 +00:00
|
|
|
ve.ce.Surface.prototype.getClickCount = function ( e ) {
|
|
|
|
if ( !$.browser.msie ) {
|
|
|
|
return e.detail;
|
|
|
|
}
|
2012-06-29 00:26:10 +00:00
|
|
|
|
2013-01-16 21:51:05 +00:00
|
|
|
var i, response = 1;
|
2012-06-29 00:26:10 +00:00
|
|
|
|
2013-01-16 21:51:05 +00:00
|
|
|
// Add select MouseEvent properties to the beginning of the clickHistory
|
|
|
|
this.clickHistory.unshift( {
|
|
|
|
x: e.x,
|
|
|
|
y: e.y,
|
|
|
|
timeStamp: e.timeStamp
|
|
|
|
} );
|
2012-06-29 00:26:10 +00:00
|
|
|
|
2013-01-16 21:51:05 +00:00
|
|
|
// Compare history
|
|
|
|
if ( this.clickHistory.length > 1 ) {
|
|
|
|
for ( i = 0; i < this.clickHistory.length - 1; i++ ) {
|
|
|
|
if (
|
|
|
|
this.clickHistory[i].x === this.clickHistory[i + 1].x &&
|
|
|
|
this.clickHistory[i].y === this.clickHistory[i + 1].y &&
|
|
|
|
this.clickHistory[i].timeStamp - this.clickHistory[i + 1].timeStamp < 500
|
|
|
|
) {
|
|
|
|
response++;
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
2012-06-29 00:26:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-16 21:51:05 +00:00
|
|
|
// Trim old history if necessary
|
2013-06-23 21:49:44 +00:00
|
|
|
if ( this.clickHistory.length > 3 ) {
|
2013-01-16 21:51:05 +00:00
|
|
|
this.clickHistory.pop();
|
|
|
|
}
|
|
|
|
|
|
|
|
return response;
|
|
|
|
};
|
|
|
|
|
2013-05-01 18:36:32 +00:00
|
|
|
/**
|
2013-07-15 23:29:30 +00:00
|
|
|
* Checks if we need to pawn for insertionAnnotations based on the related annotationSet.
|
2013-05-01 18:36:32 +00:00
|
|
|
*
|
|
|
|
* "Related" is typically to the left, unless at the beginning of a node.
|
|
|
|
*
|
2013-07-15 23:29:30 +00:00
|
|
|
* We choose to pawn if the related annotationSet doesn't match insertionAnnotations, or if
|
|
|
|
* we are at the edge of an annotation that requires pawning (i.e. an annotation requiring pawning
|
|
|
|
* is present on the left but not on the right, or vice versa).
|
|
|
|
*
|
2013-05-01 18:36:32 +00:00
|
|
|
* @method
|
|
|
|
* @param {ve.Range} selection
|
2013-07-15 23:29:30 +00:00
|
|
|
* @param {ve.dm.AnnotationSet} insertionAnnotations
|
|
|
|
* @returns {boolean} Whether we need to pawn
|
2013-05-01 18:36:32 +00:00
|
|
|
*/
|
2013-07-15 23:29:30 +00:00
|
|
|
ve.ce.Surface.prototype.needsPawn = function ( selection, insertionAnnotations ) {
|
|
|
|
var leftAnnotations, rightAnnotations, documentModel = this.model.documentModel;
|
|
|
|
|
|
|
|
function isForced( annotation ) {
|
|
|
|
return ve.ce.annotationFactory.isAnnotationContinuationForced( annotation.constructor.static.name );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( selection.start > 0 ) {
|
|
|
|
leftAnnotations = documentModel.data.getAnnotationsFromOffset( selection.start - 1 );
|
|
|
|
}
|
|
|
|
if ( selection.start < documentModel.data.getLength() ) {
|
|
|
|
rightAnnotations = documentModel.data.getAnnotationsFromOffset( selection.start + 1 );
|
|
|
|
}
|
2013-05-01 18:36:32 +00:00
|
|
|
|
|
|
|
// Take annotations from the left
|
2013-07-15 23:29:30 +00:00
|
|
|
// TODO reorganize the logic in this function
|
|
|
|
if ( leftAnnotations && !leftAnnotations.compareTo( insertionAnnotations ) ) {
|
|
|
|
return true;
|
2013-05-01 18:36:32 +00:00
|
|
|
}
|
|
|
|
// At the beginning of a node, take from the right
|
|
|
|
if (
|
The Great ve.ui.Surface refactor of 2013
Prologue:
Farewell ve.Editor my good chap… Oh, hey there HTML frames - I didn't
see you there! In a world where iframes are outlaws, and symbols like
document and window are global, there were more than a few assumptions
about which document or window was being used. But fear not - for this
commit (probably) tracks them all down, leaving a trail of
iframe-compatible awesomeness in its wake. With the great ve.ui.Surface
now able to be used inside of iframes, let the reference editing
commence. But there, lurking in the darkness is a DM issue so fierce it
may take Roan and/or Ed up to 3 whole hours to sort it out.
Note to Roan and/or Ed:
Editing references seems to work fine, but when saving the page there
are "no changes" which is a reasonable indication to the contrary.
Objectives:
* Make it possible to have multiple surfaces be instantiated, get along
nicely, and be embedded inside of iframes if needed.
* Make reference content editable within a dialog
Approach:
* Move what's left of ve.Editor to ve.ui.Surface and essentially
obliterate all use of it
* Make even more stuff inherit from ve.Element (long live this.$$)
* Use the correct document or window anywhere it was being assumed to be
the top level one
* Resolve stacking order issues by removing the excessive use of z-index
and introducing global and local overlay elements for each editor
* Add a surface to the reference dialog, load up the reference contents
and save them back on apply
* Actually destroy what we create in ce and ui surfaces
* Add recursive frame offset calculation method to ve.Element
* Moved ve.ce.Surface's getSelectionRect method to the prototype
Bonus:
* Move ve.ce.DocumentNode.css contents to ve.ce.Node.css (not sure why it
was separate in the first place, but I'm likely the one to blame)
* Fix blatant lies in documentation
* Whitespace cleanup here and there
* Get rid of ve.ui.Window overlays - not used or needed
Change-Id: Iede83e7d24f7cb249b6ba3dc45d770445b862e08
2013-05-20 22:45:50 +00:00
|
|
|
rangy.getSelection( this.$document[0] ).anchorOffset === 0 &&
|
2013-07-15 23:29:30 +00:00
|
|
|
rightAnnotations &&
|
|
|
|
!rightAnnotations.compareTo( insertionAnnotations )
|
2013-05-01 18:36:32 +00:00
|
|
|
) {
|
2013-07-15 23:29:30 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (
|
|
|
|
leftAnnotations && rightAnnotations &&
|
|
|
|
!leftAnnotations.filter( isForced ).compareTo( rightAnnotations.filter( isForced ) )
|
|
|
|
) {
|
|
|
|
return true;
|
2013-05-01 18:36:32 +00:00
|
|
|
}
|
2013-07-15 23:29:30 +00:00
|
|
|
|
|
|
|
return false;
|
2013-05-01 18:36:32 +00:00
|
|
|
};
|
|
|
|
|
2013-01-16 21:51:05 +00:00
|
|
|
/*! Getters */
|
|
|
|
|
2013-04-19 19:56:55 +00:00
|
|
|
/**
|
|
|
|
* Get the top-level surface.
|
|
|
|
*
|
|
|
|
* @method
|
2013-05-14 23:45:42 +00:00
|
|
|
* @returns {ve.ui.Surface} Surface
|
2013-04-19 19:56:55 +00:00
|
|
|
*/
|
|
|
|
ve.ce.Surface.prototype.getSurface = function () {
|
|
|
|
return this.surface;
|
|
|
|
};
|
|
|
|
|
Make use of new jshint options
* Restricting "camelcase":
No changes, we were passing all of these already
* Explicitly unrestricting "forin" and "plusplus"
These are off by default in node-jshint, but some distro of jshint
and editors that use their own wrapper around jshint instead of
node-jshint (Eclipse?) may have different defaults. Therefor
setting them to false explicitly. This also serves as a reminder
for the future so we'll always know we don't pass that, in case
we would want to change that.
* Fix order ("quotemark" before "regexp")
* Restricting "unused"
We're not passing all of this, which is why I've set it to false
for now. But I did put it in .jshintrc as placeholder.
I've fixed most of them, there's some left where there is no clean
solution.
* While at it fix a few issues:
- Unused variables ($target, $window)
- Bad practices (using jQuery context for find instead of creation)
- Redundant /*global */ comments
- Parameters that are not used and don't have documentation either
- Lines longer than 100 chars @ 4 spaces/tab
* Note:
- ve.ce.Surface.prototype.onChange takes two arguments but never
uses the former. And even the second one can be null/undefined.
Aside from that, the .change() function emits
another event for the transaction already. Looks like this
should be refactored a bit, two more separated events probably
or one that is actually used better.
- Also cleaned up a lot of comments, some of which were missing,
others were incorrect
- Reworked the contentChange event so we are no longer using the
word new as an object key; expanded a complex object into multiple
arguments being passed through the event to make it easier to work
with and document
Change-Id: I8490815a508c6c379d5f9a743bb4aefd14576aa6
2012-08-07 06:02:18 +00:00
|
|
|
/**
|
2013-01-15 23:38:49 +00:00
|
|
|
* Get the surface model.
|
Make use of new jshint options
* Restricting "camelcase":
No changes, we were passing all of these already
* Explicitly unrestricting "forin" and "plusplus"
These are off by default in node-jshint, but some distro of jshint
and editors that use their own wrapper around jshint instead of
node-jshint (Eclipse?) may have different defaults. Therefor
setting them to false explicitly. This also serves as a reminder
for the future so we'll always know we don't pass that, in case
we would want to change that.
* Fix order ("quotemark" before "regexp")
* Restricting "unused"
We're not passing all of this, which is why I've set it to false
for now. But I did put it in .jshintrc as placeholder.
I've fixed most of them, there's some left where there is no clean
solution.
* While at it fix a few issues:
- Unused variables ($target, $window)
- Bad practices (using jQuery context for find instead of creation)
- Redundant /*global */ comments
- Parameters that are not used and don't have documentation either
- Lines longer than 100 chars @ 4 spaces/tab
* Note:
- ve.ce.Surface.prototype.onChange takes two arguments but never
uses the former. And even the second one can be null/undefined.
Aside from that, the .change() function emits
another event for the transaction already. Looks like this
should be refactored a bit, two more separated events probably
or one that is actually used better.
- Also cleaned up a lot of comments, some of which were missing,
others were incorrect
- Reworked the contentChange event so we are no longer using the
word new as an object key; expanded a complex object into multiple
arguments being passed through the event to make it easier to work
with and document
Change-Id: I8490815a508c6c379d5f9a743bb4aefd14576aa6
2012-08-07 06:02:18 +00:00
|
|
|
*
|
|
|
|
* @method
|
|
|
|
* @returns {ve.dm.Surface} Surface model
|
|
|
|
*/
|
Kranitor #1: On-boarding
'''Kranitor commits''' are commits by Krinkle with his janitor hat on.
Must never contain functional changes mixed with miscellaneous changes.
.gitignore:
* Add .DS_Store to the ignore list so that browsing the directories
on Mac OS X, will not add these files to the list of untracked
files.
* Fix missing newline at end of file
.jshintrc
* raises -> throws
* +module (QUnit.module)
* remove 'Node' (as of node-jshint 1.7.2 this is now part of
'browser:true', as it should be)
Authors:
* Adding myself
MWExtension/VisualEditor.php
* Fix default value of wgVisualEditorParsoidURL to not
point to the experimental instance in WMF Labs.
Issues:
* ve.ce.TextNode:
- Fix TODO: Don't perform a useless clone of an already-jQuerified object.
- Use .html() to set html content instead of encapsulating between
two strings. This is slightly faster but more importantly safer,
and prevents situations where the resulting jQuery collection
actually contains 2 elements instead of 1, thus messing up
what .contents() is iterating over.
* ve.ce.Document.test.js
- Fix: ReferenceError: assert is not defined
* ve.dm.Document.test.js
- Fix: ReferenceError: assert is not defined
* ve.dm.Transaction.test.js
- Fix: ReferenceError: assert is not defined
* ve.dm.TransactionProcessor.test.js
- Fix: ReferenceError: assert is not defined
* ext.visualEditor.viewPageTarget
- Missing dependency on 'mediawiki.Title'
Code conventions / Misc cleanup
* Various JSHint warnings.
* Whitespace
* jQuery(): Use '<tag>' for element creation,
use '<valid><xml/></valid>' for parsing
* Use the default operator instead of ternary when the condition and
first value are the same.
x = foo ? foo : bar; -> x = foo || bar;
Because contrary to some programming language (PHP...), in JS the
default operator does not enforce a boolean result but returns the
original value, hence it being called the 'default' operator, as
opposed to the 'or' operator.
* No need to call addClass() twice, it takes a space-separated list
(jQuery splits by space and adds if needed)
* Use .on( event[, selector], fn ) instead of the deprecated
routers to it such as .bind(), .delegate() and .live().
All these three are now built-in and fully compatible with .on()
* Add 'XXX:' comments for suspicious code that I don't want to change
as part of a clean up commit.
* Remove unused variables (several var x = this; where x was not
used anywhere, possibly from boilerplate copy/paste)
* Follows-up Trevor's commit that converts test suites to the new
QUnit format. Also removed the globals since we no longer use those
any more.
Change-Id: I7e37c9bff812e371c7f65a6fd85d9e2af3e0a22f
2012-07-27 08:43:33 +00:00
|
|
|
ve.ce.Surface.prototype.getModel = function () {
|
2012-06-20 01:20:28 +00:00
|
|
|
return this.model;
|
2012-03-02 01:35:34 +00:00
|
|
|
};
|
|
|
|
|
Make use of new jshint options
* Restricting "camelcase":
No changes, we were passing all of these already
* Explicitly unrestricting "forin" and "plusplus"
These are off by default in node-jshint, but some distro of jshint
and editors that use their own wrapper around jshint instead of
node-jshint (Eclipse?) may have different defaults. Therefor
setting them to false explicitly. This also serves as a reminder
for the future so we'll always know we don't pass that, in case
we would want to change that.
* Fix order ("quotemark" before "regexp")
* Restricting "unused"
We're not passing all of this, which is why I've set it to false
for now. But I did put it in .jshintrc as placeholder.
I've fixed most of them, there's some left where there is no clean
solution.
* While at it fix a few issues:
- Unused variables ($target, $window)
- Bad practices (using jQuery context for find instead of creation)
- Redundant /*global */ comments
- Parameters that are not used and don't have documentation either
- Lines longer than 100 chars @ 4 spaces/tab
* Note:
- ve.ce.Surface.prototype.onChange takes two arguments but never
uses the former. And even the second one can be null/undefined.
Aside from that, the .change() function emits
another event for the transaction already. Looks like this
should be refactored a bit, two more separated events probably
or one that is actually used better.
- Also cleaned up a lot of comments, some of which were missing,
others were incorrect
- Reworked the contentChange event so we are no longer using the
word new as an object key; expanded a complex object into multiple
arguments being passed through the event to make it easier to work
with and document
Change-Id: I8490815a508c6c379d5f9a743bb4aefd14576aa6
2012-08-07 06:02:18 +00:00
|
|
|
/**
|
2013-01-15 23:38:49 +00:00
|
|
|
* Get the document view.
|
Make use of new jshint options
* Restricting "camelcase":
No changes, we were passing all of these already
* Explicitly unrestricting "forin" and "plusplus"
These are off by default in node-jshint, but some distro of jshint
and editors that use their own wrapper around jshint instead of
node-jshint (Eclipse?) may have different defaults. Therefor
setting them to false explicitly. This also serves as a reminder
for the future so we'll always know we don't pass that, in case
we would want to change that.
* Fix order ("quotemark" before "regexp")
* Restricting "unused"
We're not passing all of this, which is why I've set it to false
for now. But I did put it in .jshintrc as placeholder.
I've fixed most of them, there's some left where there is no clean
solution.
* While at it fix a few issues:
- Unused variables ($target, $window)
- Bad practices (using jQuery context for find instead of creation)
- Redundant /*global */ comments
- Parameters that are not used and don't have documentation either
- Lines longer than 100 chars @ 4 spaces/tab
* Note:
- ve.ce.Surface.prototype.onChange takes two arguments but never
uses the former. And even the second one can be null/undefined.
Aside from that, the .change() function emits
another event for the transaction already. Looks like this
should be refactored a bit, two more separated events probably
or one that is actually used better.
- Also cleaned up a lot of comments, some of which were missing,
others were incorrect
- Reworked the contentChange event so we are no longer using the
word new as an object key; expanded a complex object into multiple
arguments being passed through the event to make it easier to work
with and document
Change-Id: I8490815a508c6c379d5f9a743bb4aefd14576aa6
2012-08-07 06:02:18 +00:00
|
|
|
*
|
|
|
|
* @method
|
|
|
|
* @returns {ve.ce.Document} Document view
|
|
|
|
*/
|
Kranitor #1: On-boarding
'''Kranitor commits''' are commits by Krinkle with his janitor hat on.
Must never contain functional changes mixed with miscellaneous changes.
.gitignore:
* Add .DS_Store to the ignore list so that browsing the directories
on Mac OS X, will not add these files to the list of untracked
files.
* Fix missing newline at end of file
.jshintrc
* raises -> throws
* +module (QUnit.module)
* remove 'Node' (as of node-jshint 1.7.2 this is now part of
'browser:true', as it should be)
Authors:
* Adding myself
MWExtension/VisualEditor.php
* Fix default value of wgVisualEditorParsoidURL to not
point to the experimental instance in WMF Labs.
Issues:
* ve.ce.TextNode:
- Fix TODO: Don't perform a useless clone of an already-jQuerified object.
- Use .html() to set html content instead of encapsulating between
two strings. This is slightly faster but more importantly safer,
and prevents situations where the resulting jQuery collection
actually contains 2 elements instead of 1, thus messing up
what .contents() is iterating over.
* ve.ce.Document.test.js
- Fix: ReferenceError: assert is not defined
* ve.dm.Document.test.js
- Fix: ReferenceError: assert is not defined
* ve.dm.Transaction.test.js
- Fix: ReferenceError: assert is not defined
* ve.dm.TransactionProcessor.test.js
- Fix: ReferenceError: assert is not defined
* ext.visualEditor.viewPageTarget
- Missing dependency on 'mediawiki.Title'
Code conventions / Misc cleanup
* Various JSHint warnings.
* Whitespace
* jQuery(): Use '<tag>' for element creation,
use '<valid><xml/></valid>' for parsing
* Use the default operator instead of ternary when the condition and
first value are the same.
x = foo ? foo : bar; -> x = foo || bar;
Because contrary to some programming language (PHP...), in JS the
default operator does not enforce a boolean result but returns the
original value, hence it being called the 'default' operator, as
opposed to the 'or' operator.
* No need to call addClass() twice, it takes a space-separated list
(jQuery splits by space and adds if needed)
* Use .on( event[, selector], fn ) instead of the deprecated
routers to it such as .bind(), .delegate() and .live().
All these three are now built-in and fully compatible with .on()
* Add 'XXX:' comments for suspicious code that I don't want to change
as part of a clean up commit.
* Remove unused variables (several var x = this; where x was not
used anywhere, possibly from boilerplate copy/paste)
* Follows-up Trevor's commit that converts test suites to the new
QUnit format. Also removed the globals since we no longer use those
any more.
Change-Id: I7e37c9bff812e371c7f65a6fd85d9e2af3e0a22f
2012-07-27 08:43:33 +00:00
|
|
|
ve.ce.Surface.prototype.getDocument = function () {
|
2012-06-20 19:20:22 +00:00
|
|
|
return this.documentView;
|
|
|
|
};
|
2012-10-04 20:00:39 +00:00
|
|
|
|
2013-05-10 00:17:51 +00:00
|
|
|
/**
|
|
|
|
* Get the currently focused node.
|
|
|
|
*
|
|
|
|
* @method
|
|
|
|
* @returns {ve.ce.Node|undefined} Focused node
|
|
|
|
*/
|
|
|
|
ve.ce.Surface.prototype.getFocusedNode = function () {
|
|
|
|
return this.focusedNode;
|
|
|
|
};
|
|
|
|
|
2012-10-04 20:00:39 +00:00
|
|
|
/**
|
2013-09-04 22:24:08 +00:00
|
|
|
* Check whether there are any render locks
|
2013-01-15 23:38:49 +00:00
|
|
|
*
|
2012-10-04 20:00:39 +00:00
|
|
|
* @method
|
2013-09-04 22:24:08 +00:00
|
|
|
* @returns {boolean} Render is locked
|
2012-10-04 20:00:39 +00:00
|
|
|
*/
|
2013-09-04 22:24:08 +00:00
|
|
|
ve.ce.Surface.prototype.isRenderingLocked = function () {
|
|
|
|
return this.renderLocks > 0;
|
2012-10-04 20:00:39 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
2013-09-04 22:24:08 +00:00
|
|
|
* Add a single render lock (to disable rendering)
|
2013-01-15 23:38:49 +00:00
|
|
|
*
|
2012-10-04 20:00:39 +00:00
|
|
|
* @method
|
|
|
|
*/
|
2013-09-04 22:24:08 +00:00
|
|
|
ve.ce.Surface.prototype.incRenderLock = function () {
|
|
|
|
this.renderLocks++;
|
2012-10-05 21:54:32 +00:00
|
|
|
};
|
2012-12-21 18:51:20 +00:00
|
|
|
|
|
|
|
/**
|
2013-09-04 22:24:08 +00:00
|
|
|
* Remove a single render lock
|
2012-12-21 18:51:20 +00:00
|
|
|
*
|
|
|
|
* @method
|
|
|
|
*/
|
2013-09-04 22:24:08 +00:00
|
|
|
ve.ce.Surface.prototype.decRenderLock = function () {
|
|
|
|
this.renderLocks--;
|
2013-02-02 00:26:59 +00:00
|
|
|
};
|
2013-07-22 20:55:32 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Surface 'dir' property (Content-Level Direction)
|
|
|
|
* @returns {string} 'ltr' or 'rtl'
|
|
|
|
*/
|
|
|
|
ve.ce.Surface.prototype.getDir = function () {
|
2013-11-01 19:45:59 +00:00
|
|
|
return this.$element.css( 'direction' );
|
2013-07-22 20:55:32 +00:00
|
|
|
};
|
2013-09-30 21:39:49 +00:00
|
|
|
|
|
|
|
/**
|
2013-10-01 02:57:18 +00:00
|
|
|
* Change the model only, not the CE surface
|
2013-09-30 21:39:49 +00:00
|
|
|
*
|
|
|
|
* This avoids event storms when the CE surface is already correct
|
|
|
|
*
|
|
|
|
* @method
|
2013-10-01 02:57:18 +00:00
|
|
|
* @param {ve.dm.Transaction|ve.dm.Transaction[]|null} transactions One or more transactions to
|
|
|
|
* process, or null to process none
|
|
|
|
* @param {ve.Range} new selection
|
|
|
|
* @throws {Error} If calls to this method are nested
|
2013-09-30 21:39:49 +00:00
|
|
|
*/
|
2013-10-01 02:57:18 +00:00
|
|
|
ve.ce.Surface.prototype.changeModel = function ( transaction, range ) {
|
2013-09-30 21:39:49 +00:00
|
|
|
if ( this.newModelSelection !== null ) {
|
2013-10-01 02:57:18 +00:00
|
|
|
throw new Error( 'Nested change of newModelSelection' );
|
2013-09-30 21:39:49 +00:00
|
|
|
}
|
|
|
|
this.newModelSelection = range;
|
|
|
|
try {
|
2013-10-01 02:57:18 +00:00
|
|
|
this.model.change( transaction, range );
|
2013-09-30 21:39:49 +00:00
|
|
|
} finally {
|
|
|
|
this.newModelSelection = null;
|
|
|
|
}
|
|
|
|
};
|
2013-10-24 22:18:35 +00:00
|
|
|
|
|
|
|
ve.ce.Surface.prototype.setContentBranchNodeChanged = function ( isChanged ) {
|
|
|
|
this.contentBranchNodeChanged = isChanged;
|
|
|
|
};
|