instanceof Node doesn't work with nodes generated by the iframe hack
for some reason. Instead, use duck typing by checking for a .cloneNode
method.
>>> ve.createDocumentFromHTML('<body><tt>Foo</tt></body>').body.childNodes[0]
<tt>Foo</tt>
>>> ve.createDocumentFromHTML('<body><tt>Foo</tt></body>').body.childNodes[0] instanceof Node
false
Change-Id: I1ea1253bd204d1070cd01b666b8a90f1cb7e5e14
As jQuery hash problems in some cases converting HTML, it is
easier just to store the original DOM elements.
The bulk of this commit is fixing the tests as although we have an
assertion for comparing DOM elements, we don't have one for comparing
objects or arrays which may contain DOM elements.
ve.js
* copyObject & copyArray fixed to run cloneNode(true) on any item
of type Node.
* Added callback function so an object/array can be copied with
modifications.
ve.qunit.js
* Added deepEqualWithDomElements: Using the new copyObect/Array
callback, we can copy the incoming object and convert any nodes
to node summaries, then just run the normal deep equal comparison.
ve.dm.AlienNodes.js
* Instead of storing HMTL we store cloned DOM elements which we can
send straight back to the converter without any processing.
ve.dm.example.js
* Updated tests to expect DOM elements instead of HTML.
ve.dm.Converter.test.js
* Updated tests to use deepEqualWithDomElements
Bug: 47737
Change-Id: I3df8f49b170c31da9610129d53cf8cb65dd5d5f8
Previously, if we didn't know about a property type we would just drop it.
This led to various fixes to add support for booleans, nulls, etc. We're
now having problems again, this time with functions not being copied.
So instead of only copying types we know how to copy, deep clone the ones
we know how to and shallow copy the ones we don't know about. This seems
like a saner approach to me. Besides, it doesn't seem like cloning a
function is even possible in JS.
Change-Id: Idd1546ce3a43087a8b96a37101431e466e02f04f
Redone using document.implementation.createHTMLDocument instead of the
iframe trick. It's supported by all browsers we target, including IE9.
This also makes VE work on Opera using a nasty hack.
* Previously, for reasons I'm not even trying to understand, Opera
would sometimes return an empty generic object from
ve.createDocumentFromHTML() - but only if you weren't debugging it
(Dragonfly was disabled). I have no idea what is it about the iframe
hack that makes it not like it, but fact is, it doesn't work.
* Calling .open(), .write() or .close() on the document returned by
document.implementation.createHTMLDocument acts as if it was
window.document - that is, the entire contents of the web page are
replaced with new ones. That's probably a one-word bug somewhere
deep in Opera's innards; I reported it (it got the identifier
DSK-384486). Until it gets fixed, we work around it by using
document.documentElement.innerHTML, which works reliably.
Change-Id: I90ea547c735edaba9f7ecb8f685351ac6499c53e
iframe.contentDocument doesn't seem to have a key called 'document' at
all; I assume a different nesting was intended.
Change-Id: Ia37e3719d5247408bac2dfad1717d9193fb84c06
Also add detection for whether the browser is actually broken (most are,
but some, like Opera, aren't), treat <textarea> and <listing> in addition
to <pre>, and fix a bug where the function would crash if the <pre> was
empty (because .firstChild was undefined/null).
Change-Id: I541b57e9fd5c9c42d19d0a59f6e29fb43d35c9b6
addSet:
* Instead of indexing items in the store, just union the indexStore arrays
removeSet/removeNotInSet:
* difference or intersect the indexStore arrays
filter:
* push indices into the result set instead of values
simpleArrayUnion/Intersect/Difference have been created as utilities
in ve. They are prefixed 'simple' because they use object keys to
do fast in-array comparisons. This means they are limited to string
values or values which will compare as strings (e.g. numbers).
Change-Id: I079cbdfece4f6d80ec0afd61959913f13217fcb3
Instead of returning val when a custom hash is found,
feed it back into val and let the object sorting take
place if required.
Bug: 46895
Change-Id: I6a9b42facd97fbf49042d3a082121ec93659b9f1
As described in the bug, ve.getHash performs JSON.stringify so to
customise a hash the object should just return an object to be
hashed, not the hash string itself.
Bug: 46895
Change-Id: If11071d4b04a01e25102ffb57240882f650ee10d
Created an IndexValueStore class which can store any object and return
an integer index to its hash map.
Linear data is now stored in ve.dm.LinearData instances. Two subclasses
for element and meta data contain methods specific to those data types
(ElementLinearData and MetaLinearData).
The static methods in ve.dm.Document that inspected data at a given
offset are now instance methods of ve.dm.ElementLinearData.
AnnotationSets (which are no longer OrderedHashSets) have been moved
to /dm and also have to be instantiated with a pointer the store.
Bug: 46320
Change-Id: I249a5d48726093d1cb3e36351893f4bff85f52e2
Better comments for:
* ve.ce.Document.getRelativeOffset,
* ve.ce.Document.getSiblingWordBoundary.
Convert ve.ce.Surface.getSelectionRect to a static method.
Moved getNodeAndOffset from ve.ce.Surface to ve.ce.Document.
Change-Id: Ic00221fa463205d04c9b52150c0dd15904493b1e
I encountered a very difficult to track down error while working on
ve.ui.Dialog where a copy-pasted inheritClass call overwrote the
prototype of ve.ui.Widget.
By adding this check, we can ensure that 2 identical calls to
inheritClass won't silently make the system explode. This check is
lightweight and will save someone down the line a bit of time and head
scratching.
Change-Id: I014d53722fc8d941ec415462d258a79985e0e3d7
Follows-up I44bcb79a59 and various other changes.
Please remember to generate documentation and resolve
all warnings before pushing into gerrit.
Change-Id: I8a372443e841308463376d8673ce027a97bbcd30
Converts an HTML string to a brand new document using an iframe hack
(proper ways to do this exist, but don't work cross-browser).
Parsoid will serve us full HTML documents rather than document fragments
soon, so we'll need this functionality (along with some other changes
that I'm working on now) to deal with that change.
This doesn't currently work quite right in IE8 (although we have lots of
other issues in IE8) as well. It's not that hard to fix up though: we
just have to leave the iframe attached to the main document (should
probably provide a destroy function in that case) and the tests have to
deal with the fact that IE normalizes <head></head> to
<head><title></title></head> .
(For backwards compatibility, we'll have to deal with document fragments
as well; this will be implemented as an MW-specific hack in the
integration in the next commit.)
Change-Id: I15f877583c39124ba1c5e8e22585297ff3bac8d6
Follow up for I6a7c9e8ee8f995731bc205d666167874eb2ebe23
The first pass that Timo took missed the following cases
* "{Array|String}": string is just one of the values
* "{String[]}": string is followed by [] to indicate an array of strings
Change-Id: I65e595e8d37fb624802d84af9536a2d3c5d73c7d
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
Context should be 'mw', not 'mw.msg'.
Also updated to using ve.bind instead and documented that ve.msg
cannot ve.bind because the reference 've.init.platform.getMessage'
does not exist yet at run time of the ve.js file.
Change-Id: I7eb692bdc4b63cc44fab118054d8eea05c2a71ff
* Added whitelist argument to setDomAttributes which allows filtering of attributes being set
* Added prefix argument to ve.dm.Node.getAttributes to allow extracting a subset of attributes by name prefix
* Added a whitelist to ve.ce.Node which was extracted from MediaWiki's Sanitizer class
* Replaced attribute copying code with a call to setDomAttributes using the whitelist argument, passing in attributes from a call to ve.dm.Node.getAttributes using the prefix argument
Also…
* Removed comment in constructor of ve.ce.Node, documentation for properties is usually in the getters/setters, and already was in this case
* Renamed ve.setDOMAttributes to ve.setDomAttributes
* Renamed ve.getDOMAttributes to ve.getDomAttributes
* Renamed ve.getDOMText to ve.getDomText
* Renamed ve.getDOMHash to ve.getDomHash
* Updated all callers of renamed methods
Change-Id: Id556172d5d18ea431044b9d402400e1f0e67a293
* Actually return the spliced data like the docs claim we do
* Remove false claim that offset can be negative
* Add that data=[] && remove=0 is invalid; native splice() doesn't allow
this, and there is a case where we call native splice() directly
* Add tests
Change-Id: I90e77c1b22ea1c36cb61e89ea47831885a0b1cb9
Previously copyObject and copyArray would silently drop null values,
which is bad, especially considering we have example data for meta nodes
that has { 'key': null } somewhere.
Also added a test case that failed prior to this change.
Change-Id: I4f233cce041fbf38f701c494f1f78ac3d8535d88
Moved implementation of all the tools into a reusable action
system. To execute an action just call
surface.execute( actionName, method, param1, param2, ... );
This helps keep tools simple, and opens the door to key commands
reusing the same code.
Change-Id: Ie786fa3d38d1ea17d39b5dfb8eeeb5f2256267ce
Attempting to descend into a string or number would cause a JS error,
because we would attempt to create prop[arguments[i]] as an empty object
(which is ignored), then try to descend into it (which blows up because
it's undefined, even though we've just set it). Guard against this by
explicitly checking for non-object-ness.
Change-Id: Ie65550baaae0ab88476c9a1ff40cc136090740a0
The HTML "1<br/>2" was being converted to a linmod that looked like
"<p>1</p><br></br><p>2</p>". This commit fixes the wrapping logic such
that the result is "<p>1<br></br>2</p>" instead. In general, inline
nodes (content nodes) should not interrupt the wrapping, but block nodes
should.
This creates a problem for alien nodes: normally, we determine whether an
alien node is a block alien or an inline alien based on context, but if
we're in wrapping mode we're unsure of the context. We can't tell the
difference between "1<tt>Foo</tt>2" (should be wrapped as one, because
tt is inline) and "1<figure></figure>2" (1 and 2 should be wrapped
separately, because figure is block) using context alone, so in these
cases (and ONLY in these cases) we look up whether the HTML tag in
question is an inline tag or a block tag and use that to decide.
Change-Id: I75e7f3da387dd401d9b93e09a21751951eccbb83
Utility function to generate an opening HTML tag. Needed to integrate
the new annotation API with ve.ce.TextNode
Change-Id: I6804bbf6f79346fde1887fa82d29ec5cd0342d60