Commit graph

146 commits

Author SHA1 Message Date
Trevor Parscal 2473a5e7ca Static composition of 'can' and 'not', may improve performance slightly
Or at least irritate Roan less…

Change-Id: I9ea503725133ed0971f3876f199e0858c35c5aa1
2012-12-07 13:38:00 -08:00
Trevor Parscal 3002bbb591 (bug 42806) Copy/paste errors on unbalanced data
ve.ce.Surface
* Switched to using getSlice instead of getData in copy and paste handlers
* Added try/catch which attempts to build a transaction with the unbalanced data first, but falls back on the balanced data otherwise

ve.dm.*Node
* Added default style attributes (now used by ve.dm.NodeFactory)

ve.dm.Document
* Fixed bugs in fixupInsertions where parentType was being set with an object rather than a string
* Made use of getDataElement
* Added adoption capability so that inserting a</h1><p>b into <p>c[cursor]d</p> results in <p>ca</p><p>bd</p> rather than throwing an exception
* Renamed getBalancedData to getSlice, now retuning a ve.dm.DocumentSlice object

ve.dm.DocumentSlice
* Introduced new container for balanced data and a range of the original context - useful for copy/paste

ve.dm.NodeFactory
* Added getDataElement method, which uses default attributes to create a boilerplate version of a data element

ve.dm.Document.test
* Updated getBalancedData test to be a getSlice test

demos/ve/index, VisualEditor, test/index
* Added references to ve.dm.DocumentSlice

Change-Id: Id9269a29e51ca213508de8f155d3feec5e5b0774
2012-12-07 13:34:28 -08:00
Catrope 085a6f0985 (bug 42487) Don't crash the converter for "<span>\n<p>Foo</p></span>"
The converter was misbehaving when handling <p>s inside <span>s. This
can't be expressed in the linmod, but it would try to anyway. <span><p>
would result in too many paragraph closing elements, leading to an
exception in ve.dm.Document complaining about unbalanced input.
<span>\n<p> would result in an exception in the converter itself while
trying to perform whitespace preservation on the newline.

This change makes the converter detect these scenarios and alienate the
offending node. So <span><p>Foo</p></span> converts to a wrapper
paragraph containing an alienInline whose HTML is "<p>Foo</p>" and which
is annotated with a TextStyleSpanAnnotation.

ve.dm.Converter.getDomFromData():
* Change the criteria for alienBlock vs alienInline
** Only infer from the node type if we're in wrapping mode AND we're at
   the same level where the wrapping started (wrappingIsOurs). If the
   latter isn't the case, we can't split the wrapper in the block case
   because we're at the wrong level.
** Use alienInline not only if the branch is a content branch, but also
   if there are active annotations. This catches e.g. <li><b><p>
   (and generally <span><p> on the top level).
* Before converting a child element, check that the child isn't "bad".
  Bad children are non-content children in content branches, and
  non-content children encountered within a wrapper that we can't split.
  Only good children are converted, and bad children are alienated (cue
  Santa/Sinterklaas jokes).
* Add childIsContent and rename branchIsContent to branchHasContent

Change-Id: If420ae80ab0777424a9a5517335ef9d0170e87ae
2012-12-05 17:20:07 -08:00
Timo Tijhof 278e5f7640 Clean up, fix errors on demos.
* Fix 404 error for ve.ui.Icons-{raster,vector}.css
  Follows-up 9563f08 / I840f72426f9a.

makeStaticLoader.php:
* Clean up old code.
* Error out early for missing module.
* Put i18n stuff in the right place
  (some modules access ve.msg from the global scope to
  assign status variables, for standalone on demos this was
  failing due to wrong load order)

Change-Id: Idbff4c5136d567da747d9ae373cd2f6c3ee7fb1c
2012-12-04 08:58:20 +01:00
Timo Tijhof 381472ac99 init.Platform: Refactor parsed messages.
Rewrite VisualEditorMessagesModule:
* Replace copy-paste dump of user-css module with stuff for
  VisualEditor (class commend and module::$origin).
* Remove duplication between getMessages and getScript.
* Actually implement getModifiedTime so that the comment in
  getMessages() about cache invalidation is actually true
  Fixes bug 42670: ext.visualEditor.specialMessages cache broken

ve.init:
* Implement addParsedMessages and getParsedMessage so that we
  don't mix up plain messages with raw html messages (minoredit
  was previously overloaded in mw.msg storage with a parsed html
  message and retrieved though ve.msg, which is documented as
  retuning plain text, not raw html). This is now separated into
  a different method.
* Improved documentation of the other msg methods to emphasise
  their differences
* Removed redundant code in attachSaveDialog() that was
  (partially) already done in setupSaveDialog() and moved the
  remaining bits into it as well. Checked all callers of these and
  they are both only called from ViewPageTarget.prototype.onLoad
* Also implement them in the standalone platform implementation,
  with the html escaper based on mw.html.escape
* Update init.platform.getMessage to use undefined instead of
  discouraged 'if-in' statement.
* Add test suite.

demos/test:
* Re-run makeStaticLoader.php on test to add ve.init.Platform.test
* Re-run makeStaticLoader.php on demos and update i18n caller
  to use ve.init.platform.addParsedMessages (also moved out of the
  auto-generated block for easier updating)

Change-Id: I7f26b47e9467e850c08b9c217c4f1098590de109
2012-12-04 07:56:41 +01:00
Catrope e95cc34978 (bug 42469) Leading newlines in <pre>s get eaten
HTML DOM has annoying behavior for <pre>s where .innerHTML eats the
first newline in a <pre>. Work around this by explicitly adding a
newline in the data->DOM converter if the <pre> already contained a
newline.

There is a separate bug in Parsoid that causes the newline to be lost
anyway, filed as bug 42666

Change-Id: Ia26cd4a4c61afbe439b0562deb7f24ee8b8147d7
2012-12-03 17:14:33 -08:00
Trevor Parscal 23bd31a855 (bug 42555) Fixed onUpdate over-writing in ve.ce.HeadingNode
When the content rendering stuff was moved to ve.ce.ContentBranchNode the onUpdate methods being used to update the DOM wrapper in ve.ce.HeadingNode was overlooked, so heading were not rendered on update anymore.

Change-Id: I994b8c43123c3cd02b9a550d5d7eac7d5052418e
2012-11-30 11:39:46 -08:00
Trevor Parscal 5e477cbe98 (bug 42401) Cursor movement fixes
ve.ce.Surface
* Added ve.ce.Surface.adjustCursor, which replaces repetitive and buggy code that was handling left and right arrow key presses
* New method only affects the selection target, so it won't collapse the selection on you - this was what caused bug 42401
* Made hasSlugAtOffset() actually return a boolean

ve.dm.Document
* Fixed turn-around issue in ve.dm.Document.getRelativeOffset - if the offset is already valid and we can't move in the direction we want, we should just leave it be, not turn around
* Since this method was being used by ve.ce.Surface to correct the cursor position on arrow key presses, it was causing the strange cursor jumping when you pressed an arrow key while at the edge of a document

ve.dm.SurfaceFragment
* Fixed typo where getAnnotationRangeFromSelection was preserving selection direction, but checking the wrong properties

ve.dm.Document.test
* Added tests that verify turn-around issue is fixed

Change-Id: Iba55cfc3d531e7d1333b78c94912ff22179aace8
2012-11-30 09:50:47 -08:00
Catrope e148234c29 Render inline annotations in CE
Moved annotation rendering from ce.Textnode into the new
ce.ContentBranchNode class. This allows us to render annotations that
span across multiple nodes.

* Add ce.ContentBranchNode, inheriting ce.BranchNode
* Make ce.{Paragraph,Heading,Preformatted}Node inherit ce.ContentBranchNode
* Made ce.ContentBranchNode render its child nodes with anntations,
  using .getAnnotatedHtml() on the child nodes
* Put a default implementation for .getAnnotatedHtml() in ce.LeafNode
* Override this in ce.TextNode to do escaping and whitespace handling
* Removed rendering code from ce.TextNode (this.$ is now unused there)
* Removed ce.TextNode.onUpdate() and ce.BranchNode.clean(), now unneeded
* Have ce.BranchNode propagate update events from children, so
  ce.ContentBranchNode can rerender when its children change
* Update tests, add test case for escaping of &<>'"

Change-Id: I4600e984b287c6ff9267f4281d2f09bab9e1ad95
2012-11-28 11:21:59 -08:00
Catrope e123a39b4e Handle annotated inline nodes in the converter
Was broken both on the way in and on the way out.

* Move alien restoration (data->DOM) out of the main getDomFromData()
  function and into getDomElementFromDataElement(). This means the
  comment about District 9 is gone (sniff), but moving this here ensures
  all code paths hit it (previously, it was assumed annotated nodes
  could never be aliens).
* In the DOM->data converter, add annotation application to
  getDataElementFromDomElement() (for content nodes) and createAlien()
  (for aliens). Previously, these nodes would not get annotations.
** ve.AnnotationSet doesn't have a constructor that takes an array, we
   should fix that.

Change-Id: I65f8e9a322111ca3af275bf9997b0b1e7ee93769
2012-11-27 14:41:40 -08:00
Catrope 5e2c421b77 Make annotating inline elements actually work
The transaction builder would step around inline content elements when
building annotation transactions. This is now fixed.

I also tweaked the processor to tolerate attempts to annotate inline
closings. This allows the builder to generate simpler transactions,
because it doesn't have to step around the closing.

Change-Id: I1e0d7f95b38bad1b35b3e125a53350d2d126a7de
2012-11-27 14:41:40 -08:00
Catrope 49963c75fd Store the data model element in the DM tree
This is cleaner than passing around the attributes separately, and it
allows us to access the annotations in dm.LeafNode as well.

Change-Id: Ie5b90988114835831cbe5cdccf63c7cd45719e31
2012-11-27 14:36:29 -08:00
Inez Korczyński a9082e6dde Only apply HTML attributes to DOM nodes that are "safe"
* Added whitelist argument to setDomAttributes which allows filtering of attributes being set
* Added prefix argument to ve.dm.Node.getAttributes to allow extracting a subset of attributes by name prefix
* Added a whitelist to ve.ce.Node which was extracted from MediaWiki's Sanitizer class
* Replaced attribute copying code with a call to setDomAttributes using the whitelist argument, passing in attributes from a call to ve.dm.Node.getAttributes using the prefix argument

Also…

* Removed comment in constructor of ve.ce.Node, documentation for properties is usually in the getters/setters, and already was in this case
* Renamed ve.setDOMAttributes to ve.setDomAttributes
* Renamed ve.getDOMAttributes to ve.getDomAttributes
* Renamed ve.getDOMText to ve.getDomText
* Renamed ve.getDOMHash to ve.getDomHash
* Updated all callers of renamed methods

Change-Id: Id556172d5d18ea431044b9d402400e1f0e67a293
2012-11-27 14:34:29 -08:00
Catrope 1bc74b0f6d Fix tests for fda2e6c1b5
Change-Id: I2725f3f775e092bafe7aa9dca71d2a9022f16db8
2012-11-26 21:39:14 +00:00
Timo Tijhof 1ba75b7ea9 The last ever mw.ext.ve jshint fixup
Change-Id: I262673214dd59e5bcaf4e0855e68728365b041fe
2012-11-26 22:36:07 +01:00
Trevor Parscal b6139ba65e Merge "(bug 42124) Store comments in the meta-linmod" 2012-11-21 22:12:41 +00:00
Trevor Parscal f825e0093a Merge "(bug 42212) Fix JS error when inserting after alien at the end" 2012-11-21 21:56:19 +00:00
Catrope bf7b243627 (bug 42121) Change markers lost for first paragraph on new page
When editing a new page, or loading an empty page into the editor, the
converter generates a paragraph so the document isn't completely empty.
This paragraph is then unwrapped on the way out, potentially destroying
change markers and generally producing strange HTML output.

Mark this paragraph with generated=empty rather than generated=wrapper,
and only unwrap it on the way out if it's still empty. This means we
cleanly round-trip empty documents (and empty list items and the like),
but if the user enters text, we create a paragraph like we're supposed
to.

Change-Id: Id0241221a67b769445676b833b5741320d99ea5f
2012-11-21 13:54:52 -08:00
Catrope 662880605c (bug 42119) Handle alienation in wrapping mode properly
When alienating in wrapping mode, we need to look at the type of tag to
decide whether to create a wrapped alienInline, or to interrupt the
paragraph for an alienBlock.

This was being done just fine for the general alienation case
(unrecognized tag), but not for the special cases (mw:unrecognized,
about groups).

* Centralize the logic for ending a wrapper in stopWrapping()
* Move the wrapping-contingent block/inline detection logic into
  createAlien()
* Simplify the terrible if statement to decide whether a future decision
  requires us to stop wrapping. Instead, detect the cases in each code
  path separately and call stopWrapping() as appropriate
* Add tests

Change-Id: I4054584ae05e7d5daa71edead3e6a6588cf5d3bb
2012-11-21 13:42:13 -08:00
Catrope 1234a702c9 (bug 42218) Add MWEntityNode
<span typeof="mw:Entity"> tags are now correctly represented in the
model, and rendered in CE. There are still issues with cursor movement
etc. in CE.

Because the prioritization mechanism for annotations vs nodes is broken
in the current "node API", I had to hack two special cases for mw:Entity
into the converter. I also had to change the converter to ignore the
children of inline nodes (this was a legitimate bug, but had never come
up before).

Change-Id: Ib9f70437c58b4ca06aa09f7272bf51d9c41b18f2
2012-11-20 16:19:55 -08:00
Catrope 3a047e0208 (bug 42124) Store comments in the meta-linmod
* Make converter generate meta nodes with 'style': 'comment'
* Handle style==='comment' in MetaBlockNode toDOM converter
* Add some comments to the meta test case
** Update other tests accordingly
* Change getDomElementSummary() to actually assert presence of comment
  nodes (specifically, all non-text child nodes)

Change-Id: Ieef9418f4c47df3541477d9420aa2ab8df6e3df1
2012-11-19 20:01:09 -08:00
Catrope a833691421 Merge "Fixing Pre-Annotations" 2012-11-20 01:11:04 +00:00
Trevor Parscal 9c22ee346a Added undo-before-apply for new link annotations
When the link inspector is used to create a new annotation, the text is annotated with the default link target derived from the selected text. Then if the inspector is used to change that value, yet another transaction is processed when the inspector is closed.

To avoid having to press undo 2x, this change makes the inspector undo it's first change before applying the changed annotation.

This change also introduces insert, remove and select content actions.

Change-Id: I3e29189158fb01336d6b053bc2a8bda2a91a0a46
2012-11-19 17:10:05 -08:00
Christian Williams 9787166bab Fixing Pre-Annotations
AnnotationAction and SurfaceFragment now use insertAnnotations.

ve.dm.Surface.test
* Removed test for annotate method (not needed anymore)

ve.dm.SurfaceFragment
* Now using getInsertionAnnotations method
* Added support for modifying insertion annotations when annotating a zero-length selection

ve.dm.Surface
* Moved in insertion annotations state from document model
* Added insertion annotation interface (enable, disable, areEnabled, get, set, add, and remove)
* Simplified handling of annotations on change
* Removed annotate method (not used anymore)

ve.dm.Document
* Removed insertion annotations (moved it to surface model)

ve.ce.Surface
* Cleaned up handleInsertion and changed it to use the insertion annotations interface on the surface model

ve.AnnotationAction
* Moved insertion annotation handling out of here since it's now included in the surface fragment

Change-Id: I047d656acf7fa1c63f726ca2b0801e1476f84f96
2012-11-19 17:09:08 -08:00
Catrope 79e4b139fb (bug 42212) Fix JS error when inserting after alien at the end
TransactionProcessor was using parentOuterRange without checking whether
it was present, so it was exploding for indexInNode results.

Now checking for parentOuterRange presence, and falling back to
nodeOuterRange when missing.

This fix causes inconsistencies with zero-length text nodes. We should
fix these eventually, but for now I've just made the unit tests
tolerant of zero-length-text-node deviations.

Change-Id: Id9eadd57a0d5fcbaf009c0781da0a03928aebb31
2012-11-19 14:35:30 -08:00
Trevor Parscal 2c8411eb62 (bug 41947) Propagate change markers when unwrapping generated nodes
Editing the text of a list item results in a change marker on the
paragraph within that list item. However, that paragraph usually isn't
present in the HTML, so the converter unwraps it when converting back to
HTML, and the change markers are lost. Instead, transfer the change
markers to the <li>.

Change-Id: Id675075d19c08d69bc8e990174841dc393b749fc
2012-11-16 15:39:35 -08:00
Catrope 29a0c38e05 Add ce.AlienNode to tests
Change-Id: I591501067732ae36c89da340398ad35e8d4b6e3d
2012-11-16 15:35:09 -08:00
Catrope d4ea93b872 Add basic support for about groups
About groups are HTML structures like the following:
<div about="#mwt1">....</div>
<span about="#mwt1">...</span>
<div about="#mwt1">...</div>
When about groups are alienated, they are now merged into one alien
node, rather than producing a separate alien node for each sibling.

This is very basic about group handling, because it only works for
groups of directly adjacent siblings (text nodes are permitted in
between, but nothing else) assumes all about groups are aliens (which
is currently true).

* Before processing an element in the DOM->data converter, perform about
  grouping on its children. This temporarily wraps about groups in
  <div data-ve-aboutgroup="value of about attribute">
* Extended createAlien() to handle single nodes as well as wrappers
  holding multiple nodes.
* In the data->DOM converter, temporarily wrap multi-node aliens in
  <div data-ve-multi-child-alien-wrapper="true"> . This makes the rest
  of the algorithm easier.

Change-Id: I2df5f62bc222b570fc11a89fe43d353f8363ead8
2012-11-07 18:13:50 -08:00
Catrope 03827764a7 Merge "Refactored commands into a registry" 2012-11-07 23:52:59 +00:00
Trevor Parscal 443c5438ab Refactored commands into a registry
* Now ve.Factory inherits from the more general ve.Registry
* New class ve.CommandRegistry
* Refactored setupToolbar and command setup code into setupComands

Change-Id: Ic548e5de95b77889727362d3e66d7be83c12a603
2012-11-07 15:52:30 -08:00
Catrope 3d76ce60fe Merge "Replaced command factory with new command class" 2012-11-07 23:51:19 +00:00
Trevor Parscal ab57bed7da Replaced command factory with new command class
The port of mousetrap wasn't really what we needed. This is much simpler, matches the rest of our code, and does exactly what we need.

Change-Id: I67f413e097fc2d4078336edb14dd9440e771f196
2012-11-07 15:47:03 -08:00
Trevor Parscal f4a674e2c5 Merge "Flag pre nodes as having significant whitespace" 2012-11-07 22:12:45 +00:00
Trevor Parscal 273c6ac7bd Made commandFactory tests not break anymore
Sequences that were scheduled directly after each other, such as "a b c" and "1 2 3" would end up overlapping sometimes, producing "a b 1 c 2 3" which failed to trigger the correct commands.

Change-Id: I27bb60e856e9d692a21e1587dc227f8aeb5fcf4e
2012-11-07 13:56:53 -08:00
Catrope 1f01100eb9 Flag pre nodes as having significant whitespace
This causes the converter not to strip inner whitespace in them, and
causes CE to suppress the whitespace mangling logic that is normally
applied (↵ for newlines, ➞ for tabs, alternating &nbsp;s for spaces).

Change-Id: I738a750c91a4ca4836c485e282865bb7525bf30a
2012-11-07 12:10:58 -08:00
Trevor Parscal 6082953562 Made jquery.multiSuggest it's own RL module
* Also updated resource paths in tests and demo pages

Change-Id: Ic21b678f91ed8d1fe1c7ac2a53d89270aacf7c26
2012-11-06 16:37:01 -08:00
Catrope 04a999f991 Add change marking for Parsoid's benefit
* Add map of change markers per offset to Transaction
* Map is populated by TransactionProcessor
* Markers are reversed on rollback
* Removals aren't marked, Parsoid can detect these using DSR
  discontinuities

Change-Id: I2290886ab411c6ad6162044ed85c091313613e51
2012-11-06 10:11:11 -08:00
Catrope 857535b63f Introduce meta-linmod
* ve.dm.Converter still generates metaInline/metaBlock elements as
  before, it's not affected by this change
* ve.dm.Document constructor splits its input into "real" data and
  metadata
** Metadata is stored in this.metadata (the meta-linmod) as a sparse
   array of arrays, with an element for each offset in this.data
** this.data itself does not contain the metadata
** This means the node tree also doesn't contain the metadata
** Which means CE doesn't know about it at all
* All splice operations on the linear model are sent through
  ve.dm.Document.spliceData(), which performs the splice and syncs the
  meta-linmod
** Metadata in the removed range is reaped and added to the metadata for
   the offset immediately following the removal
* ve.dm.Document.getFullData() splices the linmod and meta-linmod back
  into each other; this "full data" is then fed back to ve.dm.Converter

Change-Id: Ief6dfd5b59cc13a8457993ed85c725413029c4fb
2012-11-02 19:06:49 -07:00
Catrope 6ef9fa78ff Fix ve.batchSplice() to behave in line with docs
* Actually return the spliced data like the docs claim we do
* Remove false claim that offset can be negative
* Add that data=[] && remove=0 is invalid; native splice() doesn't allow
  this, and there is a case where we call native splice() directly
* Add tests

Change-Id: I90e77c1b22ea1c36cb61e89ea47831885a0b1cb9
2012-10-30 10:05:49 -07:00
Trevor Parscal 82a15d66fc Merge "Fix copyObject/copyArray behavior with null values" 2012-10-30 16:59:02 +00:00
Catrope d30096ebd3 Fix copyObject/copyArray behavior with null values
Previously copyObject and copyArray would silently drop null values,
which is bad, especially considering we have example data for meta nodes
that has { 'key': null } somewhere.

Also added a test case that failed prior to this change.

Change-Id: I4f233cce041fbf38f701c494f1f78ac3d8535d88
2012-10-29 19:45:25 -07:00
Catrope 6df508cf8b Add InspectorFactory to tests
Tests were completely broken because the link inspector threw a JS error
when trying to register itself with the nonexistent inspector factory.

Change-Id: I8a47222f0a5a37348262ed939b37fbc47d14e222
2012-10-29 18:36:54 -07:00
Timo Tijhof 4cc2101ffd Test: Enforce # of expected assertions.
Change-Id: I041c792d1841f69677f8c7d38f67108475a0afc9
2012-10-25 22:06:07 +02:00
Krinkle dae235111c Merge "Fix JS error in ve.setProp()" 2012-10-25 19:55:16 +00:00
Catrope 84efb81e7e Fix JS error in ve.setProp()
Attempting to descend into a string or number would cause a JS error,
because we would attempt to create prop[arguments[i]] as an empty object
(which is ignored), then try to descend into it (which blows up because
it's undefined, even though we've just set it). Guard against this by
explicitly checking for non-object-ness.

Change-Id: Ie65550baaae0ab88476c9a1ff40cc136090740a0
2012-10-25 21:54:45 +02:00
Trevor Parscal 4e87a7a79b Fix number of doc sync tests
Follow up to I84f0368b1d7b601ed0766806607152dc97f34603

Change-Id: Ic1e9de1e755b8966b6e964b01b00f4d99d27245e
2012-10-25 11:06:12 -07:00
Catrope 2c1683ecff DocumentSynchronizer fix and cleanup
* Adjust the range in the annotation synchronizer, otherwise we emit
  events for the wrong node
* Expanded test suite to the point where it was able to catch the bug
  caused by not adjusting annotated ranges
* Removed selection.length === 0 check, no longer needed because
  selectNodes() now throws an exception in this case
* Added a FIXME comment about duplicate update events that occur when
  length adjustments are combined with something else
* Add a few more comments

Change-Id: I84f0368b1d7b601ed0766806607152dc97f34603
2012-10-25 11:02:58 -07:00
Trevor Parscal 8e7facf222 Merge "Guard transactions against double commit/rollback" 2012-10-25 17:55:56 +00:00
Trevor Parscal 9c51bb2d7b Merge "No longer copy data in ve.dm.Document constructor" 2012-10-25 17:54:23 +00:00
Catrope 29cff8c105 Guard transactions against double commit/rollback
* Store the applied state in the Transaction
* Store the Transaction in the TransactionProcessor (previously, only
  its operations were stored)
* Have commit() and rollback() throw exceptions when passed transactions
  with the wrong applied state
* Add tests for this behavior

Change-Id: I27b7a96fdf4d3555d78f64c05a03702ea560c802
2012-10-24 17:47:41 -07:00