Commit graph

488 commits

Author SHA1 Message Date
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
jenkins-bot 82b591bc63 Merge "Add method to ElementLinearData to get IVStore items in use" 2013-04-26 01:27:39 +00:00
jenkins-bot 38e9495d5f Merge "Make clearing by type actually work" 2013-04-26 00:47:54 +00:00
Roan Kattouw 72e06d9cbf Deduplicate childUpdate events based on transaction and appliedness
Previously, they were only being deduplicated based on the transaction,
which meant that an undo was seen as a duplicate (but then if you undid
again, that wasn't a duplicate).

Change-Id: If432ea28e6c206a2ad5562e529e2d3ed808c20e4
2013-04-25 17:08:30 -07:00
Roan Kattouw 5c5d64f5d1 Make clearing by type actually work
Clearing by type in SurfaceFragment didn't actually work. Instead,
it followed a code path intended for setting and created an annotation
of that type with no data, then tried to clear that. What we really
want to do there is clear anything with that type.

This fixes the bug where unbolding of text that was already bold in
the article didn't work.

Bug: 47680
Change-Id: I77f00e63c8732420063b0453fede7f453083c913
2013-04-25 16:53:25 -07:00
jenkins-bot 8d4c87a388 Merge "Initial support for MWBlockImageNode - thumb images with captions :-)" 2013-04-25 23:36:08 +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
Inez Korczyński 4c6d296067 Initial support for MWBlockImageNode - thumb images with captions :-)
Change-Id: I4d81533ed9193ff934333f7c1ad80e03e33b236c
2013-04-25 21:49:32 +00:00
Ed Sanders 09a90c1c7a Add method to ElementLinearData to get IVStore items in use
This is minimise the amount of data we need to serialise when
sending this over the wire.

The minimal IVStore data is added to the MW bug report, and
editedData fixed to only return the data array, not the full
LinearData object.

Documentation in AnnotationSet has finally been updated to
refelect the fact that it only stores Annotations
(was previous the generic OrderedHashSet).

getAnnotationFromOffset has been split out into a function
that just returns this indexes so that in cases where we
don't need the values we don't do an unneccesary store lookup.

Bug: 47318

Change-Id: I4819cf06d1bd0ae4f8b896052e278ca75c9551bf
2013-04-25 22:40:56 +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
Ed Sanders bdb4a116d9 Hack to escape angle brackets in data-parsoid attribute
Parsoid is sending us some unescaped HTML in the data-parsoid
attribute. When we try to rebuild ref nodes (inline aliens)
this confuses Firefox which tries to sanitise the HTML by converting
<ref/> to <ref></span>.

As a temporary fix we can manually escape <>'s inside the
data-parsoid attribute.

Also in this commit the new MWReference nodes have been moved
to experimental as they are incomplete.

Bug: 47417
Change-Id: Ib6a0cfb880e769f28b42c9fa63ddc1abc75c399d
2013-04-25 14:55:17 +01: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
Christian Williams f8f82c8eaa Selecting generated content with cursor keys
Using left and right arrow key to move to and over an image will
select the entire node.

Bug: 37870
Bug: 38129
Change-Id: I70deadd2c2707149ea33e3b8ee42fb0d8508aacc
2013-04-24 13:22:41 -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
Trevor Parscal bf254f44da UI "Views" refactor
Objective:

Make it possible for inspectors to inspect nodes or annotations, rather
than only annotations. Meanwhile, also make it possible for dialogs to
edit an annotation.

Strategy:

Switch from using type patterns to associate inspectors with annotations
to using arrays of classes, similar to how dialogs already work.
Introduce a view registry which provides lookups for relationships
between models and views. This is more centralized and less repetitive
than implement matching functions for both annotations and nodes in both
the dialog and inspector factories.

Changes:

*.php
* Added links to new file

ve.AnnotationAction.js
* Removed unused parameter to filter annotations using a string or regexp

ve.dm.AnnotationSet.js
* Switched from property/value arguments to callbacks

ve.ui.*(Dialog|Inspector).js
* Replaced type patterns with class lists
* Added class to view registry

ve.ui.*Tool.js, ve.ui.Context.js
* Updated model/view relationship lookup

ve.ui.*Factory.js
* Removed overly-specific lookup functions

ve.ui.Inspector.js
* Removed typePattern property
* Updated model/view relationship lookup

ve.ui.ViewRegistry.js
* New class!
* Migrated node and annotation lookup functions from factories

Change-Id: Ic2bbcf072fdd87e5ce8a03fe1ae3e6d8d50e2593
2013-04-18 15:53:50 -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
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 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 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
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 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
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
jenkins-bot 5764026d00 Merge "TransactionProcessor: Fix offset bug" 2013-04-14 02:51:12 +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
Ed Sanders 62c06d0253 Create GeneratedContentNode which can store rendered HTML in IV store
AlienNode is now a subclass of GCNode, but doesn't use the IV store yet.

Bug: 46571
Change-Id: If0717afdf557a2aa681d1bae3a6e98299631091a
2013-04-10 19:34:19 +01: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
Catrope 27875c8220 Reduce code duplication for annotation rendering
ve.dm.Converter and ve.ce.ContentBranchNode were duplicating a fair bit
of logic for annotation rendering. Moved the annotation opening and
closing logic into ve.dm.Converter.openAndCloseAnnotations, and
implemented both annotation rendering code paths in terms of that
function with callbacks for caller-specific behavior.

Change-Id: I7cba7d2fda7002287b07949a1b8120ba80bfe854
2013-04-09 23:38:03 +00:00
jenkins-bot 05f4579a53 Merge "Convert AnnotationFactory and MetaItemFactory to NamedClassFactories" 2013-04-09 23:20:20 +00:00
jenkins-bot 9cc2d69a27 Merge "Rename ve.NodeFactory to ve.NamedClassFactory" 2013-04-09 23:03:55 +00:00
jenkins-bot 1f0cca41a1 Merge "Add ve.ce.View as a common base class for ce.Node and ce.Annotation" 2013-04-09 22:50:29 +00:00
jenkins-bot 206a2c673c Merge "Implement next/prevBreakOffset and word skipping" 2013-04-09 22:24:41 +00:00
Ed Sanders f36e68c333 Implement next/prevBreakOffset and word skipping
This provides the functionality for keyboard word skipping
(i.e. pressing ctrl/alt + arrow key).

Bug: 46794
Change-Id: Ib0861fa075df805410717a148b8a6e166d947849
2013-04-09 21:55:57 +00:00
Catrope 162f1b4119 Convert AnnotationFactory and MetaItemFactory to NamedClassFactories
Change-Id: Ic6e3a336050a335c88ef41735c0f4e470c5b75b6
2013-04-09 12:05:05 -07:00
Catrope 9c967267e6 Rename ve.NodeFactory to ve.NamedClassFactory
We weren't really using it exclusively for nodes any more, and the only
functionality in there was for using .static.name

Change-Id: Ie26928cd01faee95a10912201663b45f1f20fb19
2013-04-09 12:05:05 -07:00
Catrope 2eb77c1298 Add ve.ce.View as a common base class for ce.Node and ce.Annotation
Just like ve.dm.Model is a common base class for dm.Node, dm.Annotation
and dm.MetaItem.

ce.View abstracts the this.model and this.$ behavior, including liveness,
whitelisted HTML attribute rendering and adding a back reference in
.data(). The back reference has been renamed from .data( 'node' ) to
the more generic .data( 'view' ).

At this point this means ce.Annotation is just a shell around ce.View
(except where it defaults to a span rather than a div), but that could
change in the future.

Change-Id: I0eef5b80718e0b0fcd3f8bba096b452f0bb680d0
2013-04-09 12:05:05 -07:00
Catrope 0b55bb8cdc Move common Node/Annotation/MetaItem code into ve.dm.Model
ve.dm.Model is now the common base class for these three. ve.dm.Node
inherited from ve.Node before, so it now uses it as a mixin instead.
This required changing ve.Node's usage of ve.EventEmitter from
inhertiance to a mixin as well, because inherited methods apparently
don't get mixed in correctly.

* Change annotation terminology from linmodAnnotation to element for
  consistency with Node, MetaItem and Model
* Reimplement getClonedElement() in Node for .internal treatment

Change-Id: Ifd3922af23557c0b0f8984d36b31c8a1e2ec497e
2013-04-09 12:05:05 -07:00
jenkins-bot 237dbe7fde Merge "Fix a bug where trimOuterSpaceFromRange() didn't trim an all-whitespace range" 2013-04-09 11:58:50 +00:00
jenkins-bot 3d0ce68893 Merge "Fix ModelRegistry bugs" 2013-04-09 11:56:14 +00:00
jenkins-bot 5029ee29ea Merge "Great Annotation Refactor of 2013" 2013-04-09 11:28:06 +00:00
Catrope 1645fe01e6 Be resilient against an unset hrefPrefix in MWCategoryMetaItem
(or any unset attribute for that matter)

Change-Id: I59364354c64fbce016090e17aa9683ec0a0fea9b
2013-04-08 21:44:59 -07:00
Catrope 2eb0d2a6b2 Great Annotation Refactor of 2013
This changes the annotation API to be the same as the node API, sans
a few boolean flags that don't apply. The APIs were different, but
there was really no good reason why, so this makes things simpler for
API users. It also means we'll be able to factor a bunch of things out
because they're now duplicated between nodes, meta items and annotations.

Linear model annotations are now objects with 'type' and 'attributes'
properties (rather than 'name' and 'data'), for consistency with elements.
They now also contain html/0/* attributes for HTML attribute preservation,
which obsoletes the htmlTagName and htmlAttributes properties.
dm.Annotation subclasses take a reference to such an object and implement
conversion using .static.toDataElement and .static.toDomElements just
like nodes do. The custom .getHash() functions are no longer necessary
because of the way HTML attribute preservation was reimplemented.

CE rendering has been moved out of dm.Annotation (it never made sense to
have CE rendering functions in DM classes, this was bothering me) and into
separate ce.Annotation subclasses. These are very similar to CE nodes in
that they have a this.$ generated based on something in the DM; the main
difference is that nodes listen to events and update themselves, whereas
annotations are static and are simply destroyed and rebuilt when they
change. This change also adds whitelisted HTML attribute rendering for
annotations, as well as class="ve-ce-FooAnnotation" attributes.

Now that annotation classes produce real DOM nodes rather than weird
objects describing HTML tags, we can't generate HTML as a string in
ce.ContentBranchNode anymore. getRenderedContents() has been rewritten
to be much more similar to the way the converter renders annotations;
in fact, significant parts of it were copied from the converter, so that
should be factored out in the future. This change actually fixes an
annotation rendering discrepancy between ce.ContentBranchNode and
dm.Converter; see the diff of ve.ce.ContentBranchNode.test.js.

ve.ce.MWEntityNode.js:
* Remove stray property

ve.dm.MWExternalLinkAnnotation.js:
* Store 'rel' attribute

ve.dm.TextStyleAnnotation.js:
* Put all the conversion logic in the abstract base class

ve.dm.Converter.js:
* Also feed annotations through getDomElementsFromDataElement() and
  createDataElement()

ve.dm.Node.js:
* Fix undocumented property

ve.ce.ContentBranchNode.test.js:
* Add descriptive messages for each test case
* Compare DOM trees, not HTML strings
* Compare without all the class="ve-ce-WhateverAnnotation" clutter

ve.ui.LinkInspector.js:
* Replace direct .getHash() calls (evil!) with ve.getHash()

Bug: 46464
Bug: 44808
Change-Id: I31991488579b8cce6d98ed8b29b486ba5ec38cdc
2013-04-08 18:10:16 -07:00
Catrope 9bac935c7d Fix ModelRegistry bugs
* In matchTypeRegExps(), skip string types
** Didn't break because we currently have mixes of strings and regexes
* Combine types from rel, typeof and property rather than picking one
** Added test case in ve.dm.example that resembles actual Parsoid output
* If the element has extension-specific types, not only restrict type
  matching to extension-specific types, but also require that *all* types
  present on the element be matched

Change-Id: Iacf3851a0ca9081d2c813b42435484a47cec6230
2013-04-08 18:05:34 -07:00
Ed Sanders 277c4f6c28 Change custom .getHash functions to .getHashObject
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
2013-04-08 23:29:56 +01:00
Catrope a0c7d90f65 Fix a bug where trimOuterSpaceFromRange() didn't trim an all-whitespace range
Also add tests for it

Change-Id: I713626bd778f45b5f7bfb6ca4ba2057f84c0a0c5
2013-04-03 16:58:51 -07:00
jenkins-bot 4d41a23b61 Merge "Store data in LinearData class with an index-value store for objects" 2013-03-30 10:17:39 +00:00
Ed Sanders fdf30b1ac8 Store data in LinearData class with an index-value store for objects
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
2013-03-30 10:06:34 +00:00
Ed Sanders 5b168bdbad Fix MWImageNode dimensions and implement toDomElements
Using element.height was returning 0 if the attribute was empty
when in fact what we mean to store is null (i.e. auto height).

This takes care of the writing of attributes in CE as jQuery
ignores an attribute-set command if the value is null.

Also in this commit I've implemented a basic toDomElements
that outputs the original HTML (code copied from AlienNode).
This stops the code from throwing an exception but will
eventually need to be rewritten to rebuild the HTML from
the attributes stored in the DM.

Bug: 56336
Change-Id: I297a1d0a07e9ebf9d0110fb1cdf266f8415f25b7
2013-03-29 12:51:43 +00:00
Inez Korczyński 21e4fdc014 Added support for displaying inline images.
Change-Id: Ieecbca8ed864585e8eaa99598d4bfdb5ac9bfec7
2013-03-28 13:05:57 -07:00
Ed Sanders 4988efd35e UnicodeJS library to implement Unicode standards
Initially just with a Wordbreak module to implement Unicode standard
on 'Default Word Boundaries'. Due to it's standaloneability this has
been written as a separate library. Non-BMP characters are currently
not supported.

Bug: 44085
Change-Id: Ieafa070076f4c36855684f6bc179667e28af2c25
2013-03-27 17:44:22 +00:00
Catrope 7e65e3becf Add insert and remove events to MetaList
These events occur when an item is inserted or removed by onTransact(),
so both for insertions/removals done through the MetaList mutators and
insertions/removals done by any other means.

We have to gather these events and batch them up because we have to allow
offset translation and index recomputation to occur first (otherwise
calling .getOffset() and .getIndex() on inserted items doesn't work).

Change-Id: I74a9a21398eca4e9afd7148171af20d439cf7ebd
2013-03-26 15:09:52 +00:00
jenkins-bot 34cc39bf9f Merge changes I4b62a310,I7c9f22a1
* changes:
  Add mutators in MetaList
  Move .commit()/.rollback() from TransactionProcessor to Document
2013-03-26 14:31:44 +00:00
jenkins-bot 14132aeb4e Merge "Docs: Primitive -> primitive." 2013-03-25 23:46:07 +00:00
Catrope 8baf7a1df9 Add mutators in MetaList
Add .insertMeta() and .removeMeta() methods to insert and remove
metadata through the meta list. For convenience, there is also a
.remove() method in MetaItem that wraps around removeMeta().

Also rename insertItem() and removeItem() to addInsertedItem() and
deleteRemovedItem() to avoid confusion, and make the MetaList
constructor take a dm.Surface rather than a document so we can call
change().

Change-Id: I4b62a3109404cfd56f5de68938e1db908b03e678
2013-03-25 21:12:20 +00:00
Ed Sanders 1cec447b59 Fix documentation to place @emits in the correct place
@emits, @returns, @chainable & @throws should always appear
in that order, according to CODING.md.

Change-Id: I9b192e018a028a8b32730c288cc4e3108800fb58
2013-03-25 21:06:05 +00:00
Catrope 1176bf9677 Move .commit()/.rollback() from TransactionProcessor to Document
Previously these were static functions in TransactionProcessor
which instantiated a TP called .process() on it. These are now
methods of ve.dm.Document.

Also moved the emission of the 'transact' event on the document from
TransactionProcessor to Document itself, and moved the tests asserting
double application is protected against from TP to Document (because
the corresponding code moved as well).

Change-Id: I7c9f22a14accaf0ba1f70d5aa4f0573bb7e677d0
2013-03-25 21:03:44 +00:00
Timo Tijhof b19a2010d8 Docs: Primitive -> primitive.
Only one left, thought there were more.

Change-Id: Ifdf490854ea138daf01319ed58cdba4182481c85
2013-03-25 18:55:08 +01:00
jenkins-bot a75b463794 Merge "Add MW-specific meta items for categories and language links" 2013-03-23 21:52:31 +00:00
Inez Korczyński c636ae138d Cleanup to ve.dm.SurfaceFragment.wordBoundaryPattern
Change-Id: I475fc0c97d5af646f51fe779c4b3136ddd3f83d0
2013-03-21 15:24:23 -07:00
Inez Korczyński 8199f2a1c1 Removed ve.dm.Document.getIEStyleWordBoundary method.
Added ve.ce.Document.getSiblingWordBoundary method.

Change-Id: I44b53273429aede5be10f39c2ee2f70d96cdc6fb
2013-03-21 14:46:13 -07:00
Catrope b39576b433 Add MW-specific meta items for categories and language links
Also rename MWMetaItem to MWAlienMetaItem, because that's what it
really is.

Change-Id: I70695bfa3b8449c936a63f7b2a248b90c49dcea1
2013-03-21 12:18:52 -07:00
Trevor Parscal c2e1350fe0 Remove more periods
Tags don't need periods at the end, these are not complete sentences.

Change-Id: I8efa931862149e892d08b370e70aff8d86a6db7d
2013-03-20 22:55:50 +00:00
jenkins-bot 0cf80096fe Merge "Document and clean up events in all the things" 2013-03-20 16:59:29 +00:00
Timo Tijhof 4e64187beb Document and clean up events in all the things
* Document them consistently between secetions Inheritance and
  Static Properties under their own (new) section Events.
* Removed any quotes or brackets around the event name in existing
  @emit annotations
  Search: @emit.*['"{}(){}]
* For every call to this.emit() anywhere, added @emits.
* Fixed all warnings for references to undefined events
  (introduced as a result of the previous point).
  Event handler parameter documented based on the emit() call
  and actual handlers using the event. Usually the latter is
  more elaborate.
* Extend coverage of jQuery as needed
  (copied from mwcore/maintenance/jsduck/external.js
  written by me, hereby implicitly and explicitly released under MIT).

Specifics
* ve.ce.Surface#onContentChange: Fixed type of range from Object to ve.Range.
* ve.ce.SurfaceObserver#poll: Fix syntax for code from {} to `backticks`.
* ve.ui.Toolbar#onContextChange: Doesn't actually emit "clearState" event.
  Removed #onClearState in Tool, ButtonTool and DropdownTool.

Bug: 45872
Change-Id: Id879aa769b2c72d86a0322e75dddeb868211ce28
2013-03-20 09:58:27 -07:00
Inez Korczyński 1c62a63bbf Introducing method ve.dm.Document.getIEStyleWordBoundary
This is just a prototype - if it will be as useful as I expect
then it will get refactored (and probably get a better name +
location).

Change-Id: Ice1a2bd7d498d9d8438c35239216f01bd3db1826
2013-03-20 16:32:38 +00:00
Catrope 00a109b4a1 Add MetaList
A MetaList is a collection of MetaItems representing all of the
metadata in a ve.dm.Document, and it updates itself live as the
underlying document changes.

Currently this interface is read-only, I'll add mutators next.

Change-Id: If7bfc9563af37e22dcdca9a682d6decc2f6f1872
2013-03-15 15:03:10 -07:00
Catrope dadf005a67 Emit a transact event on the ve.dm.Document when a transaction occurs
We'll need this to let a MetaList observe a Document and adjust to changes.
We should probably also have SurfaceFragment listen to this event instead.

Change-Id: I9e811e242969eb44afe0b4fa8153d0fb1b0071cd
2013-03-14 23:35:50 -07:00
Catrope 031b96dd2a Make metadata reaping handle replacement operations more sanely
Before, replacement operations that both inserted and removed data at
the same time would be treated as removals followed by insertions,
so we'd reap the metadata from the affected range and move it to the
start of the range. For a pure replacement, this doesn't make any sense.

Instead, preserve the first min(insertLength, removeLength) elements in
the metadata array, then perform a pure insertion splice or a pure
removal splice for the length adjustment. Any metadata reaped in a
removal splice is restored at the offset where we started removing,
after the preserved portion.

These changes make the behavior of metadata reaping saner in general
(the previous behavior had the potential to move metadata around if it
was near a paragraph opening or closing and you converted the paragraph
to a heading), and makes the behavior match up with translateOffset(),
which is desirable for MetaList synchronization.

Change-Id: If9a1c6a7cf43ead7e3e1e8f6e081b139ca65fa53
2013-03-14 23:35:50 -07:00
Catrope a835c03bc1 Change MetaNodes to MetaItems
Rather than meta-things being special kinds of nodes, they are now a
separate class of things (MetaItems) along with Nodes and Annotations.

* Created a generic ve.dm.MetaItem that meta items inherit from.
  There will be actual instances of this class as well in the upcoming
  meta group code.
* Renamed MetaNode to AlienMetaItem, MWMetaNode to MWMetaItem,
  'metaBlock'/'metaInline' to 'alienMeta'
* Created a MetaItemFactory, handle meta items in the ModelRegistry
* Kill ve.dm.Node.static.isMeta, now obsolete

ve.dm.Converter:
* Pass in the MetaItemFactory
* Look up data element types in the ModelRegistry rather than the
  NodeFactory, because they can be either nodes or meta items
* Document createDataElement() and make explicit that modelClass can be
  either a node or a meta item
* Handle meta items in getDataFromDom()
* In getDomFromData(), check the MetaItemFactory as well as the NodeFactory

Change-Id: I893709c6f3aa00f85c1b905b70f9f4e597bdeada
2013-03-14 23:35:50 -07:00
jenkins-bot 77d29ec51c Merge "Add support for non-Latin scripts to wordBoundaryPattern" 2013-03-14 18:18:38 +00:00
Ed Sanders 47090bd1fd Add support for non-Latin scripts to wordBoundaryPattern
Replacing [a-zA-Z] with a long unicode expression which encompasses
all the characters in the unicode 'letters' category. Similarly replacing
[0-9] with an expression for 'numbers'.

Bug: 44085
Change-Id: Idd403339caa24769ce08133dda06ab6d4b9d694e
2013-03-14 11:17:28 -07:00
jenkins-bot bf6e7a6361 Merge "Correct name of can(Node)HaveGrandchildren functions" 2013-03-14 18:15:43 +00:00