Commit graph

303 commits

Author SHA1 Message Date
Catrope 1765e39b40 ve.dm.Transaction: Implement newFromDocumentInsertion
This function builds a transaction that takes a document slice and
inserts it back into the document it came from, applying any changes
that were made.

This makes editing document slices simple:
    slicedDoc = doc.getDocumentSlice( captionNode );
    // Edit slicedDoc using a surface
    tx = ve.dm.Transaction.newFromDocumentInsertion( doc, captionNode, slicedDoc );
    surface.change( tx );

Specifically, newFromDocumentInsertion replaces the node's contents
with the document's contents (meaning any changes made to the node in
the meantime are lost). It also merges the stores internal lists
of the two documents and remaps indexes accordingly. This means editing
of references inside of references is supported.

This functionality is not specific to slices, and can also be used to
safely insert data from a paste buffer, with internal list data being
transplanted correctly.

ve.dm.MetaLinearData:
* Make merge( [ undefined, undefined, ... ] ) return undefined rather
  than [].

ve.dm.Document:
* In getDocumentSlice, store a pointer to the original dm.Document in
  the new one, and also store the length of the internal list. This
  allows us to figure out which internal list items the two documents
  have in common when we insert the modified slice back into the main
  document.
* In getMetadataReplace, optionally take the inserted metadata as a
  parameter, to allow for operations that insert both data and metadata.
  Per Ed's review, rewrite this function to return null rather than {}
  if no metadata needs to be replaced.

ve.dm.InternalList:
* Add method to merge two internal lists

ve.dm.Transaction:
* Remove newFromNodeReplacement and replace it with newFromDocumentInsertion.
* In pushReplace, optionally take the inserted metadata as a parameter.

Change-Id: I786ee7bad796aa54bc242993b4de3ad18ad0773e
2013-06-19 17:27:50 -07:00
jenkins-bot 8e4177c960 Merge "Only undo on MWMetaDialog close if small stack is non-empty" 2013-06-18 19:34:15 +00:00
Ed Sanders 84fbd1db2c Only undo on MWMetaDialog close if small stack is non-empty
Added return boolean to ve.dm.Surface#breakpoint to indicate if
and transactions were pushed to the big stack. Use this value in
MWMetaDialog to see if we need to undo on close.

Added tests for ve.dm.Surface#breakpoint.

Bug: 49630
Change-Id: Ieb2e9e361afe057af93c4d374acc85df58bfb4c3
2013-06-18 16:55:03 +01:00
Ed Sanders 81bdb7cf3e Store originalIndex instead of mwOriginal in Transclusions
Slightly more efficient way of seeing if the template has changed,
and results in a cleaner set of data element attributes.

Change-Id: I1507520005bfb8a88bfa6038dac5c3b15506425d
2013-06-18 15:23:37 +01:00
Roan Kattouw 177159b388 Test case for 95733390dc
Change-Id: I8c2e239e945466f3e46c92efab03f7e615bc6887
2013-06-17 17:13:45 -07:00
Roan Kattouw d32abe903e Fix selectNodes() bug with empty non-content branch nodes
These kinds of empty nodes shouldn't occur since the converter fills
them with empty paragraphs, but selectNodes() should still behave
correctly for them.

Change-Id: Ia37f3db1c2a84b842e2311cf70642fa66af04d91
2013-06-17 19:09:12 +00:00
Roan Kattouw df97f759b1 Refactor selectNodes tests
* Move them from ve.example.js to ve.dm.example.js
** Also move lookupNode() and createDomElement() there
** Delete ve.example.js because there's nothing left in it
* Make main example document implicit, but allow override
* Specify nodes as arrays and do the lookup later
* Specify range and mode separately rather than calling selectNodes()
  during construction
* Construct statically rather than in a function
* Use expect( cases.length );

Change-Id: I620e949c5e612b32eaa57c5d9b60cc91f9ddbf02
2013-06-17 20:08:08 +01:00
jenkins-bot 4cad5463d4 Merge "Code style fix: @return -> @returns" 2013-06-17 17:53:54 +00:00
Roan Kattouw 393925a868 Build the internalList linmod even if it's empty
Otherwise fun exceptions occur when you have a <references /> tag
with no <ref>s, for instance.

Also disregard the internalList in the data->DOM conversion, to prevent
a nasty interaction where the whitespace information on the last element
is considered invalid because it doesn't match the internalList's.

Plus test updates from hell because this touches ve.dm.example.data

Change-Id: I62881d9fc27fa081123856d1b35a6021af469271
2013-06-17 13:23:20 +01:00
Ed Sanders dcbea2328c Code style fix: @return -> @returns
Change-Id: I26daca6313bf09055af8f980ba0065782257fd54
2013-06-17 11:50:24 +01:00
Trevor Parscal fc8c46dd74 Reference name and group editing
Objective:

* Allow editing reference groups and names in the reference dialog

Bonus:

* Modify attribute transaction builder to support multiple attribute
  changes in a single transaction

Changes:

ve.ui.MWReferenceDialog.js
* Load ref name and group from model
* Save ref name and group, if changed, to model

ve.ui.ListAction.js, ve.ui.Transaction.test.js, ve.ce.ResizableNode.js
* Update use of newFromAttributeChange to newFromAttributeChanges

ve.dm.SurfaceFragment.test.js
* Add test for new changeAttributes method

ve.dm.InternalList.js
* Missing new line at end of file

ve.dm.Transaction.js
* Change newFromAttributeChange to accept an list of attribute changes and
  produce a single transaction that applies one or more attribute changes
  at once

ve.dm.SurfaceFragment.js
* Fix bug in getCoveredNodes where the wrong mode name was being used
* Add changeAttributes method, which applies attributes to all covered
  nodes and allows filtering of which types of nodes the attributes are
  applied to

ve.dm.MWReferenceNode.js
* Actually write key and group back to DOM
* Separate onRoot functionality into addToInternalList so it can be called
  separately (similarly onUnroot/removeFromInternalList)

ve.ce.MWReferenceListNode.js
* Clone internal item CE node before appending to avoid rendering bug.

*.php
* Add links to messages and sort them

Change-Id: Ic4121e4fcfc09265d5863af6f078cdeb77926c8e
2013-06-14 15:29:56 -07:00
Roan Kattouw 0c16066eb3 Kill attribute order preservation
Per the bug report, it's useless because Firefox does not preserve order
in the .attributes array (but sorts it alphabetically instead), and so we
actually get the same exact behavior regardless of whether we use ordering
cleverness or just a straight-up plain object: order is preserved in Chrome,
and alphabetized in Firefox.

Bug: 48980
Change-Id: I1463d06db4900083dd4c565292bbabef09194b43
2013-06-13 23:17:08 -07:00
Trevor Parscal d3a2fab2c4 Transclusion editing
Objectives:

* Rename just about every use of "template" to "transclusion"
* Make a proper data structure for transclusions
* Abstract away template data
* Use more template data in the user interface
* Allow adding parameters
* Allow removing templates, parameters and content

Changes:

ve.ui.Dialog.css
* Add rule to place add param controls on a single line

ve.ui.MWTemplateDialogs.js
* Move template spec loading into transclusion class
* Add remove button for parts and parameters
* Add parameter adding form
* Use template data for labels and descriptions

ve.dm.*
* Add new transclusion data structures

*.php
* Add links to new files

*.*
* Rename all things "template" to "transclusion"

Bug: 39598
Bug: 49403
Change-Id: I3bcf924a3e179cb65f19e833277a39dfd3dad8bd
2013-06-12 16:39:13 -07:00
Ed Sanders da51566d56 Store empty annotations as alienMeta nodes
Not a perfect solution, but better than deleting them completely.

Bug: 48605
Change-Id: I0f3a194f629b054f193a61af105733a555775d79
2013-06-12 19:46:41 +01:00
Ed Sanders 59bfc081df Store alien meta items' dom nodes only
We don't need to decompose and rebuild alien meta items
as they are uneditable, so just store the dom node and return that
in toDomElements.

Update test cases and several tests now need to use
assert.deepEqualWithDomElements.

Change-Id: I4d2eed267dac7855cb929a17d7aef566eaf0e287
2013-06-12 16:37:37 +01:00
Trevor Parscal 8039b1c2f8 Insert Reference
Objective:

* Allow opening reference dialog with arbitrary selection
* Auto-insert reference when selection is not a reference node

Changes:

ve.init.mw.ViewPageTarget.js
* Added reference button to toolbar

ve.init.Target.js
* Add getToolbarSubset so we can exclude the reference button from
  the toolbar in the reference dialog (nested references are not
  allowed).

ve.ui.MWReferenceDialog.js
* Stop storing referenceNode (not needed)
* Only store internalItem on open if there's a focused node that's a
  reference
* Use wrapper paragraph when creating a new reference
* Create new reference on dialog close if required

ve.dm.InternalList.js
* Major rewrite to support key less references.
* Add new method for creating a transaction to insert a new iternal
  item. Also returns the index of the new item to be passed to the
  reference node.

Change-Id: I839ae165c299248484ce93d4ab087318a95fbb94
2013-06-10 20:14:08 +01:00
Ed Sanders 1a86cb9c61 Preserve location of reference body within key
Previously we populated the reference body into all <ref> tags
with the same key. Now we store an internal attribute marking
which element originally had the data.

If that tag is deleted the body is moved to the first <ref> tag
with that name.

Change-Id: If9f12bfb699e6ce85bb8f7d2ea9e6df528610a3d
2013-06-10 02:54:26 +00:00
jenkins-bot cd2f411a93 Merge "Support for inline images" 2013-06-07 23:13:19 +00:00
Inez Korczyński 2f15cb0067 Support for inline images
Handles typeof mw:Image and mw:Image/Frameless

Change-Id: Ie2fbd4a3e12fb6faa4ab8e6dd0aa8d1334ff6498
2013-06-07 23:09:32 +00:00
jenkins-bot 72f661dc69 Merge "ve.dm.MWBlockImageNode: Make toDomElements add more information to its output so round-tripping can work properly." 2013-06-06 21:46:21 +00:00
jenkins-bot 8c20fb278f Merge "'typeof' for templates changed in Parsoid, it is 'Transclusion' now and used to be 'Object/Template'" 2013-06-05 23:06:15 +00:00
Inez Korczyński 2f58dd3d40 'typeof' for templates changed in Parsoid, it is 'Transclusion' now and used to be 'Object/Template'
Change-Id: Ia5b826bc1a2a648a8e618642697484000b68bfc2
2013-06-05 15:31:51 -07:00
Ed Sanders 22d1908bd4 Update reference lists and inline numberings automatically.
The easy part is getting the correct numbers from the InternalList
and generating the ordered list HTML. The tricky part is connecting
up the events to make sure the renumberings/list generations are
triggered when required.

InternalList can emit an update event on document transaction, which
triggers the renumbering/relisting if any references have been
added or deleted during that transaction.

ve.ce.MWReferenceListNode also listens to changes on the
InternalListNode (i.e. changes to the contents of the references)
and always triggers a rebuild.

Change-Id: I1b48ef5240e433c3b314259aa68cde13841ea98b
2013-06-05 15:11:16 -07:00
Inez Korczyński d14b2c514d ve.dm.MWBlockImageNode: Make toDomElements add more information to its output so round-tripping can work properly.
Change-Id: Ieacf9187371a1687869bcb4bb0244f1bc251a803
2013-06-05 14:37:28 -07:00
Timo Tijhof b463c5d377 jshint: Fix trailing comma
Due to the "es5: true" jshint option we enabled, these
warnings were surpressed. I've disabled the option since
we no longer require it. It was enabled in 07c86fc to fix
a bug with jshint. This bug has now been fixed.

Change-Id: I55b7d031eb5581af5f733f050cf2ea98dacb2af6
2013-06-05 13:00:49 +02:00
Ed Sanders 2925966944 Store DM nodes in InternalList
Also keep items in the order they appear in the document
and grouped by group and key.

Additions and removals are triggered by the new root/unroot events.

Change-Id: Ia3e90ccfdab88f352b89992b90554e5f03ff9952
2013-06-03 22:10:07 +01:00
Inez Korczyński 0b46b44809 Add class mw-figcaption to figcaption tag inside mwimage
This is currently required by Parsoid in order to serialize
(HTMLDOM -> wikitext) correctly.

Change-Id: I827f63420d05c62d689902c9b348d234f20a5d19
2013-05-28 23:21:59 +00:00
Inez Korczyński 476d10b1c3 Adjust coverter getDomSubtreeFromData method call inside ve.dm.MWBlockImageNode to pass correct arguments (there was an API change).
Change-Id: I1918aee714363babf5182c699fd96ef9fd4fce55
2013-05-28 16:01:16 -07:00
Ed Sanders c1136ca8e2 Add tests for ve.dm.InternalLists
Also fix clone method when no document supplied.

Change-Id: I7b24e8622049c6293fa0ef813696d5d91a901e75
2013-05-28 22:08:52 +01:00
jenkins-bot 5add8cc4c0 Merge "Cleanup internalList method names and data stores" 2013-05-28 14:39:14 +00:00
Ed Sanders aa6eca10db Cleanup internalList method names and data stores
Rename some methods and erase the HTML data after conversion.

Change-Id: Ic7317db2c7693591fda4bea459631981a69003f3
2013-05-28 15:11:17 +01:00
Trevor Parscal 8511f8ab3e Treat acronyms like words in camel case names
No matter what the W3C says, getDomFromHtmlString is more legible than
getDOMFromHTMLString.

Change-Id: Ic843b6671871024cce8acd82b6be435599ed168b
2013-05-28 12:51:41 +00:00
Trevor Parscal 3be13a7cbc Consistent use of mw in HTML classes, and data element and annotation types
MWfooBar or MWfoobar should be mwFooBar

Change-Id: I30f0ef05960c9df218ef6f1cb161ff6ccd529bc7
2013-05-28 13:49:56 +01:00
Catrope c36df77e3f Make reference editing work
The only reason it doesn't save correctly right now is because Parsoid
doesn't serialize reference edits correctly.

Change-Id: Ia0f272c07cc28ee829372eb848f23aec99eb92f0
2013-05-25 18:06:57 +02:00
jenkins-bot e25aa4f199 Merge "Add getDocumentSlice" 2013-05-25 11:36:37 +00:00
Catrope 6562b32aa7 Add getDocumentSlice
A document slice is a document built from a data slice of an existing
document. It's completely separate from the original document and has
its own store and internalList. The new document's data also contains
the entirety of the original document's internal list. It's possible
to create a document slice of data located inside the internal list,
in which case the resulting document will contain that data twice (one
mutable copy at the top level, and one immutable copy in the internal
list).

ve.dm.Document.js:
* Optionally take an internalList in the constructor. This allows us to
  create a document with a clone of an existing internalList rather than
  an empty one.
* Add edgeMetadata flag to getFullData()

ve.dm.IndexValueStore.js, ve.dm.InternalList.js:
* Make these classes cloneable

Change-Id: I93e06f764ace16aee9df941b07f8c2bff1a28e2b
2013-05-25 11:33:14 +00:00
jenkins-bot d6b801aa7d Merge "Store multi byte characters as one element" 2013-05-25 09:00:49 +00:00
jenkins-bot cc59e59647 Merge "Correctly populate internalList for example documents" 2013-05-24 22:55:36 +00:00
Ed Sanders 90e4f4d665 Store multi byte characters as one element
Getting & setting the cursor is done with byte offsets
instead of data model offset (characters) so we need to
be able to convert between the two as well as splitting
characters.

TODO: The regex only works on surrogate pairs, not
yet combining accents.

fixupInsertion will combine a combining mark with the
character to its left it it can.

Bug: 48630

Change-Id: I8d936fb15d82f73cd45fac142c540a7950850d55
2013-05-25 00:50:11 +02:00
Catrope 8157bcc474 Correctly populate internalList for example documents
Right now the internal list is very much HTML-based, so it's not
populated at all when creating a document from data. So hack this in by
specifying what should be in the internal list as a property of the
example document's data array.

Change-Id: I51c7b7b4dcd9fd3333777c1287b7ba544887aa32
2013-05-24 17:39:45 +02:00
Inez Korczyński 1d7cf569e6 Support for thumb and frame images with captions.
* VisualEditor.hooks.php
** export URL to magnify clip as a configuration variable so thumbnail image can render correctly

* ve.ce.Surface.css
** add CSS styling to make image captions look the same way in edit mode as they look in the view mode

* ve.ce.ParagraphNode.js
** add CSS class ve-ce-generated-wrapper if it is a generated wrapper

* ve.ce.MWImageCaptionNode.js
** make image caption rendering match the view mode

Change-Id: I0cd1b25e8f8355e0500aabc90e7c4cdf591545f3
2013-05-23 00:44:43 -07:00
Inez Korczyński 02d522500c Fix for check if data is balanced
Previous check wouldn't make sense, cause the last offset in the data
could be that one that makes data balanced (and j is increased always
after iteration).


Change-Id: Ie9498d0ac9e3417d09b8b3043bf3281e7dfbf9db
2013-05-22 14:19:42 -07:00
Catrope 7aefae885a Add a transaction builder for replacing the contents of a node
Change-Id: I69d362c4694104313dd2634434eddfbaf9435b22
2013-05-20 13:09:54 -07:00
Catrope 9ff6737f4c Refactor HTML attribute preservation
Rather than using namespaced linmod attributes, store the preserved
HTML attributes in the .htmlAttributes property of the linear model
element, in a nested structure to allow for easier treatment of child
nodes. Also added attribute order preservation by storing attributes
as an object plus an array of keys.

ve.ce.Node.js:
* Remove html/* attribute synchronization. Doesn't make sense any more
  because these things aren't in the attributes object any more. I don't
  think it ever made sense because these attributes were never supposed
  to be changed anyway.

ve.ce.View.js:
* Replace renderAttributes() with a simple wrapper around
  renderHtmlAttributeList()

ve.dm.Converter.js:
* Add buildHtmlAttributeList() and renderHtmlAttributes() for building
  and rendering HTML attribute lists

ve.dm.Model.js:
* Add getter for .htmlAttributes

ve.dm.Node.js:
* Drop .htmlAttributes on clone, and remove logic dropping html/*

ve.ui.MWCategoryWidget.js:
* Remove html/0/about hack, was already unnecessary and now doesn't
  work any more

tests/:
* UPDATE ALL THE TESTS

Change-Id: I620573afd70d36ade6b80413075b6e1f4a435abe
2013-05-17 20:57:33 -07:00
Catrope 54cd04c391 Implement ve.dm.MWTemplateNode.getWikitext()
Escapes }} and | by wrapping them in <nowiki> tags, and steps around
<nowiki> tags so as to not double-wrap things.

Change-Id: Ia50906524c1fcf55c9f390a114856bc7f20b2d3a
2013-05-15 15:16:34 -07:00
Ed Sanders 89b0dce8ec ListAction tests
Unwrap and wrap cases.

Change-Id: If4df07eae1d70347dc55b57dc117f2ff5c7385df
2013-05-13 18:59:53 +01:00
jenkins-bot ff15fbf21b Merge "Whitespace between unwrapped inline nodes assigned to paragraph" 2013-05-10 17:13:15 +00:00
Ed Sanders 328dd8e21f Whitespace between unwrapped inline nodes assigned to paragraph
In stopWrapping we assign any left over whitespace to the paragraph
in position 3, however we weren't clearing this whitespace buffer
if an inline content node followed it.

Change-Id: I8b3ee3915044abd6bafda386430bf7f992ca4aa8
2013-05-10 16:40:11 +01:00
Catrope 9372ca60ad Kill getOffsetFromNode() with fire
The way it operated was evil. It did a depth-first search from the root,
finding the node using reference equality. For documents with deep
structures, this could take a long time. Inez did some profiling and
found it was called tens of millions of times on a complex document.

Kill getOffsetFromNode() and move its functionality to getOffset().
The logic has been completely rewritten: getOffset() now traverses
up from the node rather than down from the root, and pretty much does
the reverse of what getNodeFromOffset() does. This should be much more
efficient even without offset caching in the node objects (which we may
still implement later).

Change-Id: I125f9fa423c40db6472e2c4a7c94214218ba3bc7
2013-05-09 17:26:22 -07:00
Catrope 05828cc3f1 Preserve HTML attributes recursively
For nodes that handle their own children (as well as leaf nodes and
meta items), store the first child's attributes in html/0-0/*, the
second child's attributes in html/0-1/*, the second element's third
child's fourth child's attributes in html/1-2-3/* , etc.

This obsoletes the ad-hoc code that basically did the same thing in
MWInlineImageNode.

Change-Id: If5abd2d5d9c361b359617ff4b0f3d6ba4c9b0142
2013-05-08 11:10:07 -07:00
Catrope 85d67ce44f Do proper HTML preservation in ve.dm.MWReferenceListNode
Store the HTML as a domElements array like everywhere else, rather than
as a string. Also disable HTML attribute preservation because there's
no point doing that when we're already preserving all of the HTML.

Also fixed a misnamed attribute (<li li="foo"> --> <li id="foo">) in
the test case.

Change-Id: I36bf8bade8118e07a75eb6f3a2427a00ef4915d7
2013-05-07 21:41:29 -07:00
Catrope 317a404ece Make .static.storeHtmlAttributes more versatile
It now allows you to specify which attributes to preserve in various
ways rather than just setting true or false.

Removed unused factory methods that exposed the old value.

Change-Id: I914164adcf1f0e48fa3fa85277e68c72dbad393e
2013-05-07 14:45:26 -07:00
jenkins-bot 76b277485e Merge "Fix placement of whitespace when element ends in meta" 2013-05-06 20:04:04 +00:00
Ed Sanders 830de420e1 Code style fixes
* "function(" -> "function ("
* "{String}" -> "{string}"
* collapse unintentional double spaces

Change-Id: I3ce3f02d1e31d4797b44e04d28457dec363be296
2013-05-06 12:36:52 +01:00
Roan Kattouw c801099c7b Hack MWTemplate so it also does partial type matches
For extension-specific types such as mw: , we require that all
types be matched. But we want MWTemplateNode to match
anything with an mw:Object/Template type, even if it also has
other types (like mw:WikiLink/Category in our test case).

Hack this into MWTemplate by matching on /^mw:/ then using
a matchFunction to assert that mw:Object/Template is in the
typeof attribute.

Update the test case. Because it's now a template, there's a bunch
of store stuff involved. Remove the other test case for about
group forcing because it's now a duplicate of this one.

Change-Id: Iacbe952a66d610c19b46bd76b84c50488857ac29
2013-05-05 00:07:30 -07:00
Roan Kattouw ef24ac5879 Force about grouping for multi-element about groups
When converting an element that starts an about group with at
least one other element in it, we now only consider models that
support about grouping. This prevents the first node from being
converted to something else and leaving the others hanging.

In practical terms, this means that elements like
<link rel="mw:WikiLink/Category" typeof="mw:Object/Template">
get alienated and pull in the rest of their about group, rather than
being converted to a category or alienMeta or whatever and
leaving the other elements to be converted normally.

Added a test case that asserts this. Really the result should be an
MWtemplate rather than an alien, but that's a separate issue.
Also removed superfluous mustMatchAll checks; we've already
filtered the array by the time we get there.

Change-Id: I522ba4c56d5bc52c7e9aab1e2535385540c1315d
2013-05-05 00:07:29 -07:00
Ed Sanders 8cfb4ee62f Fix placement of whitespace when element ends in meta
This was broken for both normal elements, where the meta item is
inside the element, and wrapper paragraphs, where the meta item
gets moved outside the wrapper.

Bug: 47712
Change-Id: I42daaf142e548e5b221ff0a52df0ad24ec6a4fd0
2013-05-03 22:45:34 +01:00
Ed Sanders 7cb4a30ff3 GeneratedContentNodes store DOM elements, not HTML (like aliens)
To avoid serialisation bugs, and for consistency.

Change-Id: I02e202a2ab52c88da039349ec079bea55e000665
2013-05-02 18:22:56 +01:00
James D. Forrester b9ba3c92a3 Add support for <div>s as user-editable blocks
Bug: 47907
Change-Id: I794927a881082e0113c0ce8ee8f1d908b0960899
2013-04-30 18:43:41 -07:00
Ed Sanders e29ed7f2b6 Remove all code related to change markers
Specifically by looking for "data-ve-changed",
"ChangeMarker*" and internal.changed.

Various tests, test counters and unused variables also
affected.

Bug: 45061
Change-Id: Ibd1ee68e0d650979d40574eff9cebded1a28499f
2013-04-30 23:15:47 +01:00
jenkins-bot d8d61126ea Merge "Fix range translation for surface fragments" 2013-04-30 17:58:39 +00:00
Ed Sanders d4eef1b879 Fix range translation for surface fragments
Remove all manual changes to SF ranges as these are not
undoable. Instead change translate range to default to
outer expand and build functionality around that behaviour
never changing.

As translate range is always outer I don't think we need to
check for start and end crossing over?

Added more undo tests to assert these selections are maintained
properly, and added the test case to 'update' for when and undo
point is overwritten.

Insert content now results in a selection over the inserted
content. Most usages were expecting this anyway and were
followed up with an adjustRange(-length,0) which is no longer
necessary.

Noticed that the link inspector case was never being triggered
as word boundary was always expanding to at least one char (mainly
for Hanzi selection). This doesn't make much sense as single
spaces get auto selected so removed this functionality.

Split collapseRange out into collapseRangeToStart and
collapseRangeToEnd as this may be required to get the old
behaviour (range moves to end after insert).

Change-Id: I3dc0b4d00d37bad1ca3076a69b41c5f0b3fa0570
2013-04-30 17:08:15 +01:00
Roan Kattouw a59f622d54 Per Timo's comment, change $.makeArray( foo ) to foo.toArray()
Change-Id: Ideee46640bc82f979578d5cc467c9c79d9806ae0
2013-04-29 18:08:04 -07:00
Ed Sanders b85c7f0628 Create meta item for defaultsort
Bug: 46465
Change-Id: I604a79c25e5b0315f7e6437da657977b0efa77db
2013-04-29 15:33:37 +01:00
Ed Sanders 6aaa54bc5f Fix new test case to use new domElements instead of html
This was missed by the merge as it doesn't cause any tests to fail (yet).

Change-Id: I6d106279d31276817ea718fdef3d8199b80693f6
2013-04-28 21:24:20 +01:00
jenkins-bot e7d335b1c7 Merge "Paragraph->heading conversion was broken when cursor next to an inline node" 2013-04-28 20:01:08 +00:00
Ed Sanders cddb3f1b39 AlienNode stores original DOM elements instead of HTML
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
2013-04-27 21:04:58 +00:00
Roan Kattouw e89e991037 Paragraph->heading conversion was broken when cursor next to an inline node
In this case, selectNodes() returns the paragraph, which is not a content
node, and so newFromContentBranchConversion() decides to do nothing at all.

This change makes newFromContentBranchConversion() more intelligent about
finding the content branch to operate on, fixing cases such as these
where selectNodes() returns the content branch itself rather than one of
its children.

Bug: 41203
Change-Id: I710fbf184ef5ef84d9c2f5bca2b115e0660f5b8f
2013-04-27 00:16:46 +00:00
Ed Sanders 60cf31bcb6 Allow fixUpInsertion to move offsets when inserting at start/end
fixUpInsertion now returns an object with both data and offset
which allows offset changes.

Within fixUpInsertion we lazy-generate first/lastChildStack which
is a list of parent nodes for which the current node is the first/last
child. Whenever we try to close off a node we check these stacks and
if they are populated we instead use a recursive call to start
fixUpInsertion again but with the offset shifted by 1.

Bug: 46799

Change-Id: Ic51dd03725c11f1f7e279929534ee3afea14d662
2013-04-26 22:52:27 +00:00
Roan Kattouw c68765639a Add TableCaptionNode
Because we have a node for <table>, we also need one for <caption>,
otherwise we'll try to alienate it and fail.

Added the test case as a separate example document so Ed can use it
for his tests.

Removed test case asserting <caption> is alienated.

Change-Id: I3a917db58e6c0eb97899b214b07d01fc8d86b56d
2013-04-26 14:09:54 -07:00
jenkins-bot af4868badc Merge "Further AnnotationSet optimisation: create containsIndex" 2013-04-26 01:28:20 +00:00
Ed Sanders 3d64c3043c Further AnnotationSet optimisation: create containsIndex
In most places we call .contains we already know the index, so we
can avoid store lookups by using .containsIndex.

Change-Id: I45a9a421473f9bec479ab8ccceceb162b7004c3a
2013-04-25 22:55:43 +01:00
Ed Sanders cd4ee24c0e Remove fixUpStack to fix blank paragraph insertion bug
The fixUpStack is actually redundant code and closingStack
and openingStack handle all our cases. It was causing the
insertion to try to correct balance itself in the middle
of inserting two paragraphs, causing the creation on an
empty paragraph between them.

Added a test case for the fix and other cases to make
sure removing fixUpStack hasn't caused problems.

Bug: 46800

Change-Id: I35e54165709ac56e8116359a7c3b487eecf08ff7
2013-04-25 14:04:51 -07:00
Inez Korczyński 6b7d62e4a4 Rename MWImageNode to MWInlineImageNode (get ready for adding MWBlockImageNode soon)
Change-Id: I617e2a17cb6fbd11e486c2981e361ae931ac1870
2013-04-24 16:49:07 -07:00
Ed Sanders 6ad61d4ddb Add data model support for MediaWiki references
So far just read-only.

Bug: 39599
Change-Id: I6daff5c5969e5fdc871f8f346cf790b4302ae080
2013-04-23 10:17:42 +01:00
jenkins-bot e7fb5d9cce Merge "AnnotationSet optimisations." 2013-04-22 21:20:15 +00:00
jenkins-bot 196123e7a5 Merge "MWTemplateNode should serialise original HTML if unchanged" 2013-04-22 21:15:41 +00:00
Ed Sanders 2bd6f8576a MWTemplateNode should serialise original HTML if unchanged
To help the selective serialiser we can return the original
HTML for generated content if it is unmodified.

As the output of toDomElements now depends on changes
to the dataElement we now have a 'modify' function in
the some test cases.

We also now have 'storeItems' to assert that the index-value
store is correctly populated and for loading values back
into the store for toDomElements tests.

Also make 'mw' an attribute and remove 'about' property.

Bug: 47394
Change-Id: I2bbb5d2d6a90c4eb87fa129671112c92a9b931e7
2013-04-22 20:44:21 +00:00
Catrope 3848c3f220 Factor the <pre> newline hack out of the converter into ve.properInnerHTML()
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
2013-04-22 20:09:52 +01:00
Ed Sanders 1998496e49 AnnotationSet optimisations.
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
2013-04-22 19:37:19 +01:00
Ed Sanders 8b09dd7650 The resurrection
By removing the transaction listeners from surface fragments we
no longer have to make sure they are always manually destroyed.

In order to retain the functionality of having fragments update
with transactions elsewhere we keep a pointer to a place in the
new complete history stack in the surface. The complete history
stack records all transactions, even undone ones.

Whenever getRange is called we replay all transactions in the
complete history (in the correct order) since the fragment was
last updated.

Also in this commit:
* Updated Format/IndentationAction to test undo(). This increases
  coverage of surface fragment behaviour.
* .range is always accessed by .getRange now, although as an
  optimisation we can use the noCopy mode when we a sure the
  returned range will not be modified.
* Added undo test to .update (previously .onTransact)

Bug: 47343
Change-Id: I9e9818da1baa8319a3002f6d74fd1aad6732a8f5
2013-04-22 12:50:23 +01:00
Catrope 83a592f312 Fix whitespace preservation around meta items
This was broken, especially in wrappers.

Changed the wrapping algorithm so that meta items are placed outside
wrappers if possible. On the left-hand side, this is already the case:
we don't open wrappers for meta items. On the right-hand side, this is
accomplished by buffering the meta items and only inserting them when
we encounter either real text (not whitespace) or the end of the wrapper.
If we're interrupted by real text, we insert the meta items with the
unmodified whitespace. If we're interrupted by the end of the wrapper,
we insert the meta items outside of the wrapper with whitespace stripped.

Internally, this is done by stripping the whitespace into the whitespace[0]
of the meta item to its right. Then when we output the meta items, we
either decide to 'restore' the whitespace, or to 'fixup' by also setting
whitespace[3] on the element before the whitespace.

Change-Id: Ibeea2a9906c4aae9fe6d284613edd6ec853ca5e7
2013-04-18 16:06:58 -07:00
jenkins-bot 889e62a0ff Merge "Remove html/* attributes in getClonedElement()" 2013-04-18 22:32:24 +00:00
jenkins-bot d28c5548d5 Merge "Make the AnnotationSet constructor take an array of indexes" 2013-04-18 21:50:25 +00:00
jenkins-bot 22622c922b Merge "Death and/or destruction" 2013-04-18 20:58:19 +00:00
Trevor Parscal 2419f7638c Death and/or destruction
So. It turns out that the design of SurfaceFragment is a little -
shall we say - wonky.

One of the best things about ve.dm.SurfaceFragment is its magical
ability to retain the intention of its range, even as transactions
are being processed. This ability is granted by each fragment
listening to the surface's change event, and responding by using
translateRange for each transaction that gets processed. Surface
fragments also have these clever methods that allow you to get a
fragment based on another, which makes adjusting the range easy to do
inline without having to manually store multiple fragments or
modifying the original.

This sounded good, and we seemed to all be convinced it was well
designed. But if you add a console.log( 'hello' ); to the first line
of ve.dm.SurfaceFragment.prototype.onTransact, and then start using
the bold tool on various selections of text, you will find that there
may indeed be a flaw. What you will probably realize is that the
number of times that particular line of code is being called is
disturbingly large, and increases each time you do just about anything
in the editor. What's going on? How did we get here? Read on…

It turns out that fragments are immortal. We create them, they listen
to the surface's transact event, we are done with them, but the
surface keeps on emitting events to the now long forgotten about
fragments. They continue to build up over time, never go out of scope,
and bloat the hell out of our program.

The same ended up being true of toolbars - and each time the context
menu fired up a new one the old one was left in limbo, still
responding to events, still taking up memory, but not being visible to
the user.

All of this immortality was causing strange and difficult to track
down problems. This patch fixes this by introducing a destroy method.
This method unbinds events, allowing the object to finally fall out of
scope and die - and more importantly stop receiving notifications of
changes.

This is a hack, but Ed will no doubt get this situation sorted out
properly by making fragments lazy-evaluate their selections by only
storing an identifier of the most recent transaction they were based
on, see bug 47343.

Change-Id: I18bb986001a44732a7871b9d79dc3015eedfb168
2013-04-18 13:56:20 -07:00
jenkins-bot d54cf4c131 Merge "Transactions to store metadata merge info when present" 2013-04-18 20:04:51 +00:00
Catrope eac44c39f4 Make the AnnotationSet constructor take an array of indexes
Before, it took an array of objects and translated those to indexes
using the store. Literally every caller outside of the test suite got
an array of indexes from the linear model, translated those to objects,
then passed them into the AnnotationSet constructor which translated
them right back to indexes.

The previous behavior was kind of ridiculous on its face, but the
reason we found it is because Inez was investigating the performance
degradation when bolding a line and found that half of it was due
to the hundreds of ve.getHash() calls caused by this behavior.

Change-Id: I38df8ae9f6392849dacf477ea2f804283c964417
2013-04-18 10:56:03 -07:00
Catrope 533e43ea80 Remove html/* attributes in getClonedElement()
Subbu said that cloning of attributes like data-parsoid or typeof would
cause problems for Parsoid.

Also remove the attributes object if it becomes empty, and do the same
for the internal object.

Bug: 47297
Change-Id: I428becf95c70d0ed8af5b0c408e3966dc47fd8c3
2013-04-18 09:27:28 -07:00
jenkins-bot 16d164ed6d Merge "Delete spurious normalizedHtml" 2013-04-18 15:32:53 +00:00
jenkins-bot 17a93e96ec Merge "Serialize alienated context-sensitive nodes correctly" 2013-04-18 11:10:37 +00:00
Catrope 42c1aa10cd Serialize alienated context-sensitive nodes correctly
Context-sensitive nodes are HTML elements like <caption> that can only
appear in certain contexts (<table> in this case). This means that
serializing them by throwing them in a <div> and calling .innerHTML
fails, because the browser knows a <caption> can't be in a <div> and
unwraps it. jQuery's .html() function is clever though and knows to wrap
<caption> in a <table> (and has similar rules for other elements).
So use jQuery's .html() rather than manual .innerHTML stuff.

Change-Id: Id7d3eff968b3a2ba345680772f7cc32e3dcdb529
2013-04-17 18:26:54 -07:00
Catrope 50e14d42d4 Delete spurious normalizedHtml
Was equal to the HTML before conversion, so not needed

Change-Id: I48e3b3d48334562f605bccfddc5f2aa7cf883087
2013-04-17 17:54:35 -07:00
Catrope 2f1ee49213 Fix a weird whitespace stripping bug
In HTML like <td>Foo <b>Bar</b></td>, the space would be stripped and
registered as trailing whitespace in the <td>, so it wouldn't be visible
in the editor and would be inserted after the </b> on the way out.

Thanks to Subbu for reporting this. This case was kind of ridiculous and
we're lucky the JRuby article contained it. To trigger the bug, you had
to have:
* a table cell
* containing unwrapped content
* consisting of
** some text
** whitespace
** open annotation (bold in my example, link in Subbu's case)
** text
** close annotation
** and nothing else

Change-Id: I2b83f02764b311a32a50956d4c8930a9394e91a4
2013-04-17 17:08:47 -07:00
Catrope 04516bb02e Whitespace preservation was broken after the first run
The first run of getDomFromData() would preserve whitespace just fine,
but it blanked out the .veInternal.whitespace[1] element in certain
cases, contaminating the linear model and making the whitespace data
inconsistent. Subsequent runs of getDomFromData() would then refuse to
serialize that whitespace because the information about it was
inconsistent.

In getDomFromData(), we sometimes unset .veInternal.whitespace[1] (i.e.
set it to undefined) to prevent double processing. Because we're
potentially going to modify .veInternal, don't assign it by reference,
but copy the object.

Added tests asserting that the linear model is unchanged after calling
getDomFromData(), because that function should never modify
linear model data. This test failed in 4 cases (all whitespace-related)
before I added the copyObject() call.

Bug: 43543
Change-Id: Ic4c93510518163894201a693ab50331413715967
2013-04-17 11:28:05 +00:00
Ed Sanders ff7b8a2591 Transactions to store metadata merge info when present
ve.dm.Transaction
* Replace operations are now built directly from the
  linear model and automatically determine what metadata
  replace information they need to include:
** retainMetadata
** replaceMetadata
** insertMetadata

ve.dm.Document
* Metadata array created empty and padded out after data parsing
  as we are no longer using Document.spliceData to build it (a new
  test checks for correct metadata length)
* spliceData replaced with getMetadataReplace, which instead returns
  transactional steps of spliceData (retain, replace, insert)

ve.dm.MetaLinearData
* Add function for merging metadata items together. Only used
  once in the code (Document.getMetadataReplace) but useful
  for generating test data.

ve.dm.MetaList
* Replace operations with metadata need to calculate new offset
  and indices directly, but can't be applied immediately lest they
  put a metaItem out of place and affect findItem.

ve.dm.MetaItem
* Add methods to support queued moves as required by MetaList

Test files
* Updated to match new pushReplace API
* Remove any instances of Document.spliceData
* Extra check on sparse metadata array length
* Rewrite spliceData tests as getMetadataReplace tests
* Count expected cases in Transaction(Processor) tests

Bug: 46954
Change-Id: I4edad1c2dd37c723bff2792bab7d694ef17a86dc
2013-04-16 22:26:56 +01:00
Ed Sanders 6dacc54954 Hybridise MWTemplateNode
* Create MWTemplateBlockNode & MWTemplateInlineNode (in ce and dm)
* Move Alien's 'isInline' code to ve.dm.Node.static.isHybridInline
* Move definition of ce.AlienBlock/InlineNode inside ce.Aline.js file
  to match dm.AlienBlock/InlineNode and MWTemplate
* Duplicate AlienBlock/Inline styles for templates
* Create test case for inline templates
* Count test cases in ve.dm.Converter.test.js automatically

Change-Id: Id9bc7f049ea974dd5e7f8b7a66080939e0948bbd
2013-04-14 02:34:18 +00:00
Ed Sanders 01eda7f36a Create MWTemplateNode
This node stores the rendered in the index-value store, hashed on
a custom hash of the dm (type + mw) which makes it unique it its
parameters.

Bug: 46571
Change-Id: I0ab4c9f7bca207121d5b42e83c821771b6139da8
2013-04-11 23:58:48 +01:00
Trevor Parscal 9510440640 Image node refactor
ve.ce.ImageNode.js
* Moved in generic stuff from MWImageNode
* Added drag end handler (empty, will be used soon)

ve.ce.MWImageNode.js
* Changed to inherit ImageNode
* Moved generic stuff out

ve.dm.ImageNode.js
* Added attribute extraction/preservation for src, width and height

ve.dm.MWImageNode.js
* Changed to inherit ImageNode
* Re-using ImageNode's attribute handling to extract/preserve attributes on both the image and wrapper level

Change-Id: Ied4e1ece24e6804220eac35330790f7084df55de
2013-04-10 14:56:08 -07:00
Catrope 316fdab450 Actually use the doc parameter in toDomElements()
It's been passed in for a while, but nothing ever used it. As we know
some browsers don't like it when we create elements in the wrong
document, and this ensures we always use the correct document for
createElement().

Change-Id: Ia3d2fabe0516956105ad2b5625ed2f76c015c26e
2013-04-09 23:48:03 +00:00