Commit graph

1396 commits

Author SHA1 Message Date
jenkins-bot 267d800415 Merge "Actually pass oldid parameter when serializing" 2013-04-18 22:34:17 +00: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 d03aaa102c Merge changes I7b0e3fa4,I559232f3
* changes:
  ve.init.mw.ViewPageTarget: Put the Edit source link in the visible tab area
  ve.init.mw.ViewPageTarget: Switch tabLayout from 'add' to 'replace'
2013-04-18 21:02:23 +00:00
jenkins-bot eac3cb99e0 Merge "Added inline comment explaining not obvious purpose of code" 2013-04-18 20:59: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
Inez Korczyński d809dc7e37 Added inline comment explaining not obvious purpose of code
Change-Id: Ib9ea1307ebe58c03abd00dcf8b96681d6901a3d4
2013-04-18 13:39:56 -07:00
jenkins-bot d54cf4c131 Merge "Transactions to store metadata merge info when present" 2013-04-18 20:04:51 +00:00
jenkins-bot 1bfc9594b3 Merge "Avoid rendering content of ve.ce.ContentBranchNode multiple times when only one transaction is applied" 2013-04-18 18:58:42 +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 289116c493 Merge "When we say originalHtml, we'd better mean it" 2013-04-18 15:27:25 +00:00
Catrope cdba5f2800 When we say originalHtml, we'd better mean it
Gabriel noticed whitespace diffs in the problem reports. These were
caused by browsers' .innerHTML being broken on <pre>s. We compensate
for this in the converter, but not when generating originalHtml.

However, a variable called originalHtml really shouldn't be generated,
it should just literally be the original, unprocessed HTML. This
does mean it includes the doctype, <html> and <head> which aren't
included in editedHtml (that one's just the contents of the <body>), but
that's much easier to deal with on Parsoid's end than random newline
diffs all over the place.

Change-Id: I8e66cb79887f49f84114ab6b4d0e0d24aea744b6
2013-04-18 08:09:50 -07:00
jenkins-bot 17a93e96ec Merge "Serialize alienated context-sensitive nodes correctly" 2013-04-18 11:10:37 +00:00
jenkins-bot 52a666956c Merge "Fix a weird whitespace stripping bug" 2013-04-18 10:56:17 +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 6c1e4cfdd2 Partly fix the "Report problem" button
This was broken ever since the introduction of IndexValueStore, because
the call to getDataFromDom() wasn't updated, so it crashed with a "doc
is undefined" error. Fixing part of this by passing in a new IVStore.

The data that is transmitted over the wire still has indices with no way
to find out what the corresponding annotations are. It needs to be fully
expanded but there's no way to do this in DM quite yet.

Bug: 47319
Change-Id: I761523d22e51ac560e37ae991d01a6b84224ca40
2013-04-17 23:04:56 +00:00
Inez Korczyński e786c5c2f0 Avoid rendering content of ve.ce.ContentBranchNode multiple times when only one transaction is applied
Change-Id: I940bb96b670afb7ab3de524919b56912d027a2ef
2013-04-17 12:16:04 -07:00
Catrope eab968d7f0 ve.init.mw.ViewPageTarget: Put the Edit source link in the visible tab area
Instead of in the collapsed section.

Change-Id: I7b0e3fa4e35ce6135e3a47360da51fd8e0231ca1
2013-04-17 18:15:43 +00:00
Catrope 116321afe5 Make the "Report problem" POST URL configurable
Defaults to "$wgVisualEditorParsoidURL/_bugs/"

Change-Id: I4847d54b0effe433d5d179d91fdf361c249515ad
2013-04-17 17:05:58 +00:00
Catrope 4511a9e6be Actually pass oldid parameter when serializing
Apparently Parsoid has always required this, and we've never sent it,
yet somehow the code in production works. This may well be the cause
of some of the selser issues we saw after the deployment attempt in
January.

Made oldid a required parameter in the API module, and default it to 0.
When we get 0, we translate that to the empty string for Parsoid's
benefit. We also need to explicitly get wgCurRevisionId in
ViewPageTarget, and that's also 0 on new pages.

Change-Id: I3a55025246014cd74e15d6d5b6c4ede7b823e5df
2013-04-17 11:31:20 +00: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
Catrope 9a98d8bce4 ve.init.mw.ViewPageTarget: Switch tabLayout from 'add' to 'replace'
This makes the Edit tab point to the VisualEditor, and adds a
"Edit source" link to the p-cactions menu.

Bug: 46872
Change-Id: I559232f3d8e42df0d45311b65df8c30425b1a368
2013-04-17 10:25:36 +00:00
jenkins-bot 1b072d2e0c Merge "Inside ve.ce.Document.getRelativeOffset fallback to 'character' mode if 'word' mode returns the same offset as was passed originally" 2013-04-16 22:54:27 +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
Inez Korczyński 9d5b9525d6 Inside ve.ce.Document.getRelativeOffset fallback to 'character' mode if 'word' mode returns the same offset as was passed originally
Change-Id: Ia3de5d5c1f37f17161fb1c8c9a284c868bb4a5fb
2013-04-16 13:12:25 -07:00
jenkins-bot 11f4bbbb9d Merge "There was no check if anchorNode of selection range is inside an element with CSS class ve-ce-slug." 2013-04-16 18:35:36 +00:00
jenkins-bot 5000cbaa80 Merge "Make returning the same offset the least preferred option in ve.ce.Document.getRelativeOffset" 2013-04-16 18:26:54 +00:00
Catrope 383a669f7c Fix annotation breakage
Inez reported that unitalicizing from the toolbar was broken, because
the toolbar was somehow generating annotations that had .attributes={}
as opposed to .attributes=undefined. Turned out the cause was in the
default value for element in the ve.dm.Model constructor.

Change-Id: I64ea9ef56cd15d1131c1aa23484d7420c95a8225
2013-04-15 17:04:50 -07:00
Inez Korczyński d4e41e2908 Make returning the same offset the least preferred option in ve.ce.Document.getRelativeOffset
Change-Id: If21cdea220b58aec92b8735e92f594d8c16c8f6f
2013-04-15 14:59:04 -07:00
Inez Korczyński 097fd3c1a4 There was no check if anchorNode of selection range is inside an element with CSS class ve-ce-slug.
Adding that check let me simplify logic around a little bit as well.

Bug: 47258

Change-Id: I51bf5e9caecf6a8b4e0f75118a93cfe69a5a6542
2013-04-15 21:40:13 +00:00
jenkins-bot 887465b159 Merge "Filter our zero-coverage updateState nodes" 2013-04-14 02:53:01 +00:00
jenkins-bot 5764026d00 Merge "TransactionProcessor: Fix offset bug" 2013-04-14 02:51:12 +00:00
Trevor Parscal 504a1bafd0 Filter our zero-coverage updateState nodes
Added filter for nodes being passed to update state event - this
ensures that nodes are not being included with zero-length coverage, a
side effect of how selectNodes handles the virtual boundaries of text
nodes.

Change-Id: I6362114b57469b1108da11f94dc345a2bcdfc7cd
2013-04-14 02:50:01 +00: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
jenkins-bot 1b5f4704ff Merge "Have ce's ctrl+arrow functionality use UnicodeJS library" 2013-04-13 08:06:20 +00:00
Inez Korczyński 77d9606bde TransactionProcessor: Fix offset bug
Use ve.BranchNode.getNodeFromOffset instead of
ve.dm.Document.getNodeFromOffset so correct nodes will be retrieved to
emit update events to.


Change-Id: Iaf559f0424584a3dde065e548e403c4a53207312
2013-04-12 23:16:51 +00:00
Ed Sanders 7f6beb9d39 Have ce's ctrl+arrow functionality use UnicodeJS library
Change 57076 implemented the functionality required to skip
words in UnicodeJS. This change simply removes all the existing
code we had and replaces it with this implementation.

Bug: 46794
Change-Id: I6b2700d65476c4d34ba4a01a88382d7af8e736fb
2013-04-12 12:12:53 +01: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
Catrope 54a232a92b Allow nodes to handle their own children
For data->DOM, this is easy: .toDataElements() can optionally return an
array instead of an object, and that will be treated as the data to
insert. If this happens, the converter won't descend. The node handler
can recursively invoke the converter if it needs to (although I suspect
the current implementation is broken when converting block content in an
inline context).

For DOM->data, this is a bit more complex. The node sets
.static.handlesOwnChildren = true; , which triggers the converter to
pass a data slice rather than a single data element, and not to
descend. The node handler can invoke the converter to recursively
convert DOM subtrees to data.

ve.dm.Converter (data->DOM):
* Renamed createDataElement() to createDataElements()
** .toDataElement() may return element or array, handle this
* Renamed childDataElement to childDataElements, is now an array
* Actually alienate if .toDataElement() returns null
** Shockingly, this claimed to be supported before but wasn't
* Rather than pushing to data, concat to it
** Add closing if needed
* Don't descend if .toDataElement() returned an array of length >1, or
  if the node has .handlesOwnChildren = true

ve.dm.Converter (DOM->data):
* Split getDomSubtreeFromData() and getDomFromData()
* When converting a node that handles its own children, pass in a data
  slice and skip over that data

Change-Id: I196cb4c0895cbf0b428a189adb61b56565573ab3
2013-04-11 22:41:18 +00:00
jenkins-bot 6123f6e952 Merge "Fixes to DM metaList stuff under Roan's guidance." 2013-04-11 22:32:38 +00:00
Rob Moen 1c6522d9e9 Fixes to DM metaList stuff under Roan's guidance.
Splitting this out of https://gerrit.wikimedia.org/r/#/c/58274

Change-Id: Ic90b9714959e1cfb0c18997e2f2b593ed9909990
2013-04-11 14:49:17 -07:00
Catrope 1b5a376c28 Allow hybrids across Model subclasses
A node could already implement a toDataElements() function that
returns a data element of another node type, but it couldn't return
an annotation or a meta item. This is fixed now, and any dm.Model
subclass can now morph into any other dm.Model subclass.

I didn't originally plan to do this today at all, but doing this now
makes my upcoming converter changes easier. Surprise feature!

Change-Id: Ief6ac302094df084221a5a97c32a522b929c2960
2013-04-11 11:12:44 -07:00
Catrope 76b080dce1 Pass the converter object to the node handler in toDataElement()
This will allow node handlers to recursively invoke getDataFromDomRecursion()

Change-Id: I12cd4b31614a549bfbe8fbdc7d0607ece32aa98a
2013-04-11 11:12:44 -07:00
Catrope daaf255f13 Make getDataFromDomRecursion() use a context stack to pass context info
This will allow toDataElement() functions to just call this function
with a DOM element, rather than having to have all the recursion context
data to pass in.

Also expose this information using getters.

Change-Id: I89574c42385267e08704f018c0892d63014376a6
2013-04-11 11:12:39 -07: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