mediawiki-extensions-Visual.../modules/ve/test/dm/ve.dm.Converter.test.js

119 lines
3.4 KiB
JavaScript
Raw Normal View History

JSDuck: Generated code documentation! See CODING.md for how to run it. Mistakes fixed: * Warning: Unknown type function -> Function * Warning: Unknown type DOMElement -> HTMLElement * Warning: Unknown type DOM Node -> HTMLElement * Warning: Unknown type Integer -> Mixed * Warning: Unknown type Command -> ve.Command * Warning: Unknown type any -> number * Warning: Unknown type ve.Transaction -> ve.dm.Transaction * Warning: Unknown type ve.dm.AnnotationSet -> ve.AnnotationSet * Warning: Unknown type false -> boolean * Warning: Unknown type ve.dm.AlienNode ve.dm doesn't have a generic AlienNode like ve.ce -> Unknown type ve.dm.AlienInlineNode|ve.dm.AlienBlockNode * Warning: Unknown type ve.ve.Surface -> ve.ce.Surface * ve.example.lookupNode: -> Last @param should be @return * ve.dm.Transaction.prototype.pushReplace: -> @param {Array] should be @param {Array} * Warning: ve.BranchNode.js:27: {@link ve.Node#hasChildren} links to non-existing member -> (removed) * Warning: ve.LeafNode.js:21: {@link ve.Node#hasChildren} links to non-existing member -> (removed) Differences fixed: * Variadic arguments are like @param {Type...} [name] instead of @param {Type} [name...] * Convert all file headers from /** to /*! because JSDuck tries to parse all /** blocks and fails to parse with all sorts of errors for "Global property", "Unnamed property", and "Duplicate property". Find: \/\*\*([^@]+)(@copyright) Replace: /*!$1$2 * Indented blocks are considered code examples. A few methods had documentation with numbered lists that were indented, which have now been updated to not be intended. * The free-form text descriptions are parsed with Markdown, which requires lists to be separated from paragraphs by an empty line. And we should use `backticks` instead of {braces} for inline code in text paragraphs. * Doc blocks for classes and their constructor have to be in the correct order (@constructor, @param, @return must be before @class, @abstract, @extends etc.) * `@extends Class` must not have Class {wrapped} * @throws must start with a {Type} * @example means something else. It is used for an inline demo iframe, not code block. For that simply indent with spaces. * @member means something else. Non-function properties are marked with @property, not @member. * To create a link to a class or member, in most cases the name is enough to create a link. E.g. Foo, Foo.bar, Foo.bar#quux, where a hash stands for "instance member", so Foo.bar#quux, links to Foo.bar.prototype.quux (the is not supported, as "prototype" is considered an implementation detail, it only indexes class name and method name). If the magic linker doesn't work for some case, the verbose syntax is {@link #target label}. * @property can't have sub-properties (nested @param and @return values are supported, only @static @property can't be nested). We only have one case of this, which can be worked around by moving those in a new virtual class. The code is unaltered (only moved down so that it isn't with the scope of the main @class block). ve.dm.TransactionProcessor.processors. New: * @mixins: Classes mixed into the current class. * @event: Events that can be emitted by a class. These are also inherited by subclasses. (+ @param, @return and @preventable). So ve.Node#event-attach is inherited to ve.dm.BreakNode, just like @method is. * @singleton: Plain objects such as ve, ve.dm, ve.ce were missing documentation causing a tree error. Documented those as a JSDuck singleton, which they but just weren't documented yet. NB: Members of @singleton don't need @static (if present, triggers a compiler warning). * @chainable: Shorthand for "@return this". We were using "@return {classname}" which is ambiguous (returns the same instance or another instance?), @chainable is specifically for "@return this". Creates proper labels in the generated HTML pages. Removed: * @mixin: (not to be confused with @mixins). Not supported by JSDuck. Every class is standalone anyway. Where needed marked them @class + @abstract instead. Change-Id: I6a7c9e8ee8f995731bc205d666167874eb2ebe23
2013-01-04 08:54:17 +00:00
/*!
* VisualEditor DataModel Converter tests.
*
* @copyright 2011-2013 VisualEditor Team and others; see AUTHORS.txt
* @license The MIT License (MIT); see LICENSE.txt
*/
Kranitor #1: On-boarding '''Kranitor commits''' are commits by Krinkle with his janitor hat on. Must never contain functional changes mixed with miscellaneous changes. .gitignore: * Add .DS_Store to the ignore list so that browsing the directories on Mac OS X, will not add these files to the list of untracked files. * Fix missing newline at end of file .jshintrc * raises -> throws * +module (QUnit.module) * remove 'Node' (as of node-jshint 1.7.2 this is now part of 'browser:true', as it should be) Authors: * Adding myself MWExtension/VisualEditor.php * Fix default value of wgVisualEditorParsoidURL to not point to the experimental instance in WMF Labs. Issues: * ve.ce.TextNode: - Fix TODO: Don't perform a useless clone of an already-jQuerified object. - Use .html() to set html content instead of encapsulating between two strings. This is slightly faster but more importantly safer, and prevents situations where the resulting jQuery collection actually contains 2 elements instead of 1, thus messing up what .contents() is iterating over. * ve.ce.Document.test.js - Fix: ReferenceError: assert is not defined * ve.dm.Document.test.js - Fix: ReferenceError: assert is not defined * ve.dm.Transaction.test.js - Fix: ReferenceError: assert is not defined * ve.dm.TransactionProcessor.test.js - Fix: ReferenceError: assert is not defined * ext.visualEditor.viewPageTarget - Missing dependency on 'mediawiki.Title' Code conventions / Misc cleanup * Various JSHint warnings. * Whitespace * jQuery(): Use '<tag>' for element creation, use '<valid><xml/></valid>' for parsing * Use the default operator instead of ternary when the condition and first value are the same. x = foo ? foo : bar; -> x = foo || bar; Because contrary to some programming language (PHP...), in JS the default operator does not enforce a boolean result but returns the original value, hence it being called the 'default' operator, as opposed to the 'or' operator. * No need to call addClass() twice, it takes a space-separated list (jQuery splits by space and adds if needed) * Use .on( event[, selector], fn ) instead of the deprecated routers to it such as .bind(), .delegate() and .live(). All these three are now built-in and fully compatible with .on() * Add 'XXX:' comments for suspicious code that I don't want to change as part of a clean up commit. * Remove unused variables (several var x = this; where x was not used anywhere, possibly from boilerplate copy/paste) * Follows-up Trevor's commit that converts test suites to the new QUnit format. Also removed the globals since we no longer use those any more. Change-Id: I7e37c9bff812e371c7f65a6fd85d9e2af3e0a22f
2012-07-27 08:43:33 +00:00
QUnit.module( 've.dm.Converter' );
/* Tests */
// TODO rewrite to test getDataElementOrAnnotationFromDomElement
/*
QUnit.test( 'getDataElementFromDomElement', 20, function ( assert ) {
Kranitor #1: On-boarding '''Kranitor commits''' are commits by Krinkle with his janitor hat on. Must never contain functional changes mixed with miscellaneous changes. .gitignore: * Add .DS_Store to the ignore list so that browsing the directories on Mac OS X, will not add these files to the list of untracked files. * Fix missing newline at end of file .jshintrc * raises -> throws * +module (QUnit.module) * remove 'Node' (as of node-jshint 1.7.2 this is now part of 'browser:true', as it should be) Authors: * Adding myself MWExtension/VisualEditor.php * Fix default value of wgVisualEditorParsoidURL to not point to the experimental instance in WMF Labs. Issues: * ve.ce.TextNode: - Fix TODO: Don't perform a useless clone of an already-jQuerified object. - Use .html() to set html content instead of encapsulating between two strings. This is slightly faster but more importantly safer, and prevents situations where the resulting jQuery collection actually contains 2 elements instead of 1, thus messing up what .contents() is iterating over. * ve.ce.Document.test.js - Fix: ReferenceError: assert is not defined * ve.dm.Document.test.js - Fix: ReferenceError: assert is not defined * ve.dm.Transaction.test.js - Fix: ReferenceError: assert is not defined * ve.dm.TransactionProcessor.test.js - Fix: ReferenceError: assert is not defined * ext.visualEditor.viewPageTarget - Missing dependency on 'mediawiki.Title' Code conventions / Misc cleanup * Various JSHint warnings. * Whitespace * jQuery(): Use '<tag>' for element creation, use '<valid><xml/></valid>' for parsing * Use the default operator instead of ternary when the condition and first value are the same. x = foo ? foo : bar; -> x = foo || bar; Because contrary to some programming language (PHP...), in JS the default operator does not enforce a boolean result but returns the original value, hence it being called the 'default' operator, as opposed to the 'or' operator. * No need to call addClass() twice, it takes a space-separated list (jQuery splits by space and adds if needed) * Use .on( event[, selector], fn ) instead of the deprecated routers to it such as .bind(), .delegate() and .live(). All these three are now built-in and fully compatible with .on() * Add 'XXX:' comments for suspicious code that I don't want to change as part of a clean up commit. * Remove unused variables (several var x = this; where x was not used anywhere, possibly from boilerplate copy/paste) * Follows-up Trevor's commit that converts test suites to the new QUnit format. Also removed the globals since we no longer use those any more. Change-Id: I7e37c9bff812e371c7f65a6fd85d9e2af3e0a22f
2012-07-27 08:43:33 +00:00
var msg, conversion;
Kranitor #1: On-boarding '''Kranitor commits''' are commits by Krinkle with his janitor hat on. Must never contain functional changes mixed with miscellaneous changes. .gitignore: * Add .DS_Store to the ignore list so that browsing the directories on Mac OS X, will not add these files to the list of untracked files. * Fix missing newline at end of file .jshintrc * raises -> throws * +module (QUnit.module) * remove 'Node' (as of node-jshint 1.7.2 this is now part of 'browser:true', as it should be) Authors: * Adding myself MWExtension/VisualEditor.php * Fix default value of wgVisualEditorParsoidURL to not point to the experimental instance in WMF Labs. Issues: * ve.ce.TextNode: - Fix TODO: Don't perform a useless clone of an already-jQuerified object. - Use .html() to set html content instead of encapsulating between two strings. This is slightly faster but more importantly safer, and prevents situations where the resulting jQuery collection actually contains 2 elements instead of 1, thus messing up what .contents() is iterating over. * ve.ce.Document.test.js - Fix: ReferenceError: assert is not defined * ve.dm.Document.test.js - Fix: ReferenceError: assert is not defined * ve.dm.Transaction.test.js - Fix: ReferenceError: assert is not defined * ve.dm.TransactionProcessor.test.js - Fix: ReferenceError: assert is not defined * ext.visualEditor.viewPageTarget - Missing dependency on 'mediawiki.Title' Code conventions / Misc cleanup * Various JSHint warnings. * Whitespace * jQuery(): Use '<tag>' for element creation, use '<valid><xml/></valid>' for parsing * Use the default operator instead of ternary when the condition and first value are the same. x = foo ? foo : bar; -> x = foo || bar; Because contrary to some programming language (PHP...), in JS the default operator does not enforce a boolean result but returns the original value, hence it being called the 'default' operator, as opposed to the 'or' operator. * No need to call addClass() twice, it takes a space-separated list (jQuery splits by space and adds if needed) * Use .on( event[, selector], fn ) instead of the deprecated routers to it such as .bind(), .delegate() and .live(). All these three are now built-in and fully compatible with .on() * Add 'XXX:' comments for suspicious code that I don't want to change as part of a clean up commit. * Remove unused variables (several var x = this; where x was not used anywhere, possibly from boilerplate copy/paste) * Follows-up Trevor's commit that converts test suites to the new QUnit format. Also removed the globals since we no longer use those any more. Change-Id: I7e37c9bff812e371c7f65a6fd85d9e2af3e0a22f
2012-07-27 08:43:33 +00:00
for ( msg in ve.dm.example.conversions ) {
conversion = ve.dm.example.conversions[msg];
assert.deepEqual(
ve.dm.converter.getDataElementFromDomElement( conversion.domElement ),
conversion.dataElement,
msg
);
}
} );
*/
QUnit.test( 'getDomElementsFromDataElement', 20, function ( assert ) {
var msg, conversion, doc;
Kranitor #1: On-boarding '''Kranitor commits''' are commits by Krinkle with his janitor hat on. Must never contain functional changes mixed with miscellaneous changes. .gitignore: * Add .DS_Store to the ignore list so that browsing the directories on Mac OS X, will not add these files to the list of untracked files. * Fix missing newline at end of file .jshintrc * raises -> throws * +module (QUnit.module) * remove 'Node' (as of node-jshint 1.7.2 this is now part of 'browser:true', as it should be) Authors: * Adding myself MWExtension/VisualEditor.php * Fix default value of wgVisualEditorParsoidURL to not point to the experimental instance in WMF Labs. Issues: * ve.ce.TextNode: - Fix TODO: Don't perform a useless clone of an already-jQuerified object. - Use .html() to set html content instead of encapsulating between two strings. This is slightly faster but more importantly safer, and prevents situations where the resulting jQuery collection actually contains 2 elements instead of 1, thus messing up what .contents() is iterating over. * ve.ce.Document.test.js - Fix: ReferenceError: assert is not defined * ve.dm.Document.test.js - Fix: ReferenceError: assert is not defined * ve.dm.Transaction.test.js - Fix: ReferenceError: assert is not defined * ve.dm.TransactionProcessor.test.js - Fix: ReferenceError: assert is not defined * ext.visualEditor.viewPageTarget - Missing dependency on 'mediawiki.Title' Code conventions / Misc cleanup * Various JSHint warnings. * Whitespace * jQuery(): Use '<tag>' for element creation, use '<valid><xml/></valid>' for parsing * Use the default operator instead of ternary when the condition and first value are the same. x = foo ? foo : bar; -> x = foo || bar; Because contrary to some programming language (PHP...), in JS the default operator does not enforce a boolean result but returns the original value, hence it being called the 'default' operator, as opposed to the 'or' operator. * No need to call addClass() twice, it takes a space-separated list (jQuery splits by space and adds if needed) * Use .on( event[, selector], fn ) instead of the deprecated routers to it such as .bind(), .delegate() and .live(). All these three are now built-in and fully compatible with .on() * Add 'XXX:' comments for suspicious code that I don't want to change as part of a clean up commit. * Remove unused variables (several var x = this; where x was not used anywhere, possibly from boilerplate copy/paste) * Follows-up Trevor's commit that converts test suites to the new QUnit format. Also removed the globals since we no longer use those any more. Change-Id: I7e37c9bff812e371c7f65a6fd85d9e2af3e0a22f
2012-07-27 08:43:33 +00:00
for ( msg in ve.dm.example.conversions ) {
conversion = ve.dm.example.conversions[msg];
doc = conversion.domElement.ownerDocument;
assert.equalDomElement(
ve.dm.converter.getDomElementsFromDataElement( conversion.dataElement, doc )[0],
conversion.domElement,
msg
);
}
} );
QUnit.test( 'getDataFromDom', function ( assert ) {
var msg, doc, store, internalList, i, length, hash, n = 0,
cases = ve.copyObject( ve.dm.example.domToDataCases );
// TODO: this is a hack to make normal heading/preformatted
// nodes the most recently registered, instead of the MW versions
ve.dm.modelRegistry.register( ve.dm.HeadingNode );
ve.dm.modelRegistry.register( ve.dm.PreformattedNode );
for ( msg in cases ) {
if ( cases[msg].html !== null ) {
n++;
if ( cases[msg].storeItems ) {
n += cases[msg].storeItems.length;
}
}
}
QUnit.expect( n );
Kranitor #1: On-boarding '''Kranitor commits''' are commits by Krinkle with his janitor hat on. Must never contain functional changes mixed with miscellaneous changes. .gitignore: * Add .DS_Store to the ignore list so that browsing the directories on Mac OS X, will not add these files to the list of untracked files. * Fix missing newline at end of file .jshintrc * raises -> throws * +module (QUnit.module) * remove 'Node' (as of node-jshint 1.7.2 this is now part of 'browser:true', as it should be) Authors: * Adding myself MWExtension/VisualEditor.php * Fix default value of wgVisualEditorParsoidURL to not point to the experimental instance in WMF Labs. Issues: * ve.ce.TextNode: - Fix TODO: Don't perform a useless clone of an already-jQuerified object. - Use .html() to set html content instead of encapsulating between two strings. This is slightly faster but more importantly safer, and prevents situations where the resulting jQuery collection actually contains 2 elements instead of 1, thus messing up what .contents() is iterating over. * ve.ce.Document.test.js - Fix: ReferenceError: assert is not defined * ve.dm.Document.test.js - Fix: ReferenceError: assert is not defined * ve.dm.Transaction.test.js - Fix: ReferenceError: assert is not defined * ve.dm.TransactionProcessor.test.js - Fix: ReferenceError: assert is not defined * ext.visualEditor.viewPageTarget - Missing dependency on 'mediawiki.Title' Code conventions / Misc cleanup * Various JSHint warnings. * Whitespace * jQuery(): Use '<tag>' for element creation, use '<valid><xml/></valid>' for parsing * Use the default operator instead of ternary when the condition and first value are the same. x = foo ? foo : bar; -> x = foo || bar; Because contrary to some programming language (PHP...), in JS the default operator does not enforce a boolean result but returns the original value, hence it being called the 'default' operator, as opposed to the 'or' operator. * No need to call addClass() twice, it takes a space-separated list (jQuery splits by space and adds if needed) * Use .on( event[, selector], fn ) instead of the deprecated routers to it such as .bind(), .delegate() and .live(). All these three are now built-in and fully compatible with .on() * Add 'XXX:' comments for suspicious code that I don't want to change as part of a clean up commit. * Remove unused variables (several var x = this; where x was not used anywhere, possibly from boilerplate copy/paste) * Follows-up Trevor's commit that converts test suites to the new QUnit format. Also removed the globals since we no longer use those any more. Change-Id: I7e37c9bff812e371c7f65a6fd85d9e2af3e0a22f
2012-07-27 08:43:33 +00:00
for ( msg in cases ) {
Preserve whitespace between elements This commit fully utilizes all four positions in the internal.whitespace array. Outer whitespace is now preserved as well, and is duplicated either in the adjacent sibling (one node's outerPost is the next sibling's outerPre) or in the parent (a branch node's innerPre is its first child's outerPre, and its innerPost is its last child's outerPost). Before restoring saved whitespace, we check that these two agree with each other, and if they disagree we assume the user has been moving stuff around and don't restore any whitespace in that spot. The whitespace at the very beginning and the very end of the document (i.e. the first node's outerPre and the last node's outerPost) isn't duplicated anywhere, nor is inner whitespace in content nodes. The basic outline of the implementation is: * When we encounter whitespace, strip it and store it in the previous node's outerPost. Also store it in nextWhitespace so we can put it in the next node's outerPre once we encounter that node. * When we encounter whitespace in wrapped bare text, we don't know in advance if it's gonna be succeeded by more non-whitespace (in which case it needs to be output verbatim), or not (in which case it's leading whitespace and needs to be stripped and stored). The fact that annotations are nodes in HTML makes this trickier. So we write the whitespace to the temporary linmod and store it in wrappedWhitespace, then if it turns out to be trailing whitespace we take it back out of the data array and record it the usual way. * Because text nodes can contain any combination of leading whitespace actual text and trailing whitespace, and because we may or may not already have opened a wrapping paragraph, there are a lot of different combinations to handle. We handle all of them but the resulting code is pretty dense and verbose. More low-level list of changes: In getDataFromDom(): * Added helper function addWhitespace() for storing whitespace for an element * Added helper function processNextWhitespace() for processing any whitespace passed on from the previous node via the nextWhitespace var * Rename paragraph to wrappingParagraph. Make wrapping default to alreadyWrapped so we can simplify wrapping||alreadyWrapped and !wrapping&&!alreadyWrapped. Add wrappingIsOurs to track whether the wrapping originated in this recursion level (needed for deciding when to close the wrapper). * Add prevElement to track the previous element so we can propagate whitespace to it, and nextWhitespace so we can propagate whitespace to the next element. * Remove previous newline stripping hacks * Integrate the logic for wrapping bare content with the outer whitespace preservation code * Remove wrapperElement, no longer needed because we have a dedicated variable for the wrapping paragraph now and what was previously inner whitespace preservation for wrapper paragraphs is now covered by the outer whitespace preservation code. In getDomFromData(): * Reinsert whitespace where appropriate ** outerPre is inserted when opening the element ** This covers outerPost as well except for the last child's outerPost, which is handled as the parent's innerPost when closing the parent. ** innerPre and innerPost are inserted when closing the element. Care is taken not to insert these if they're duplicates of something else. * Propagate each node's outerPost to the next node (either the next sibling or the parent) using parentDomElement.lastOuterPost. We can't get this using .lastChild because we will have destroyed that child's .veInternal by then, and we can't tell whether a node will be its parent's last child when we process it (all other processing, including first child handling is done when processing the node itself, but this cannot be). * Special handling is needed for the last node's outerPost, which ends up in the container's .lastOuterPost property. Tests: * Allow .html to be null in data<->DOM converter tests. This indicates that the test is a one-way data->DOM test, not a DOM->data->DOM round-trip test. The data will be converted to HTML and checked against .normalizedHtml * Update existing tests as needed * Add tests for outer whitespace preservation and storage * Add test for squashing of whitespace in case of disagreement (this requires .html=null) Change-Id: I4db4fe372a421182e80a2535657af7784ff15f95
2012-08-21 00:37:42 +00:00
if ( cases[msg].html !== null ) {
doc = new ve.dm.Document( [] );
store = doc.getStore();
internalList = doc.getInternalList();
ve.dm.example.preprocessAnnotations( cases[msg].data, store );
assert.deepEqualWithDomElements(
ve.dm.converter.getDataFromDom(
ve.createDocumentFromHtml( cases[msg].html ), store, internalList
).getData(),
Preserve whitespace between elements This commit fully utilizes all four positions in the internal.whitespace array. Outer whitespace is now preserved as well, and is duplicated either in the adjacent sibling (one node's outerPost is the next sibling's outerPre) or in the parent (a branch node's innerPre is its first child's outerPre, and its innerPost is its last child's outerPost). Before restoring saved whitespace, we check that these two agree with each other, and if they disagree we assume the user has been moving stuff around and don't restore any whitespace in that spot. The whitespace at the very beginning and the very end of the document (i.e. the first node's outerPre and the last node's outerPost) isn't duplicated anywhere, nor is inner whitespace in content nodes. The basic outline of the implementation is: * When we encounter whitespace, strip it and store it in the previous node's outerPost. Also store it in nextWhitespace so we can put it in the next node's outerPre once we encounter that node. * When we encounter whitespace in wrapped bare text, we don't know in advance if it's gonna be succeeded by more non-whitespace (in which case it needs to be output verbatim), or not (in which case it's leading whitespace and needs to be stripped and stored). The fact that annotations are nodes in HTML makes this trickier. So we write the whitespace to the temporary linmod and store it in wrappedWhitespace, then if it turns out to be trailing whitespace we take it back out of the data array and record it the usual way. * Because text nodes can contain any combination of leading whitespace actual text and trailing whitespace, and because we may or may not already have opened a wrapping paragraph, there are a lot of different combinations to handle. We handle all of them but the resulting code is pretty dense and verbose. More low-level list of changes: In getDataFromDom(): * Added helper function addWhitespace() for storing whitespace for an element * Added helper function processNextWhitespace() for processing any whitespace passed on from the previous node via the nextWhitespace var * Rename paragraph to wrappingParagraph. Make wrapping default to alreadyWrapped so we can simplify wrapping||alreadyWrapped and !wrapping&&!alreadyWrapped. Add wrappingIsOurs to track whether the wrapping originated in this recursion level (needed for deciding when to close the wrapper). * Add prevElement to track the previous element so we can propagate whitespace to it, and nextWhitespace so we can propagate whitespace to the next element. * Remove previous newline stripping hacks * Integrate the logic for wrapping bare content with the outer whitespace preservation code * Remove wrapperElement, no longer needed because we have a dedicated variable for the wrapping paragraph now and what was previously inner whitespace preservation for wrapper paragraphs is now covered by the outer whitespace preservation code. In getDomFromData(): * Reinsert whitespace where appropriate ** outerPre is inserted when opening the element ** This covers outerPost as well except for the last child's outerPost, which is handled as the parent's innerPost when closing the parent. ** innerPre and innerPost are inserted when closing the element. Care is taken not to insert these if they're duplicates of something else. * Propagate each node's outerPost to the next node (either the next sibling or the parent) using parentDomElement.lastOuterPost. We can't get this using .lastChild because we will have destroyed that child's .veInternal by then, and we can't tell whether a node will be its parent's last child when we process it (all other processing, including first child handling is done when processing the node itself, but this cannot be). * Special handling is needed for the last node's outerPost, which ends up in the container's .lastOuterPost property. Tests: * Allow .html to be null in data<->DOM converter tests. This indicates that the test is a one-way data->DOM test, not a DOM->data->DOM round-trip test. The data will be converted to HTML and checked against .normalizedHtml * Update existing tests as needed * Add tests for outer whitespace preservation and storage * Add test for squashing of whitespace in case of disagreement (this requires .html=null) Change-Id: I4db4fe372a421182e80a2535657af7784ff15f95
2012-08-21 00:37:42 +00:00
cases[msg].data,
msg
);
// check storeItems have been added to store
if ( cases[msg].storeItems ) {
for ( i = 0, length = cases[msg].storeItems.length; i < length; i++ ) {
hash = cases[msg].storeItems[i].hash || ve.getHash( cases[msg].storeItems[i].value );
assert.deepEqualWithDomElements(
store.value( store.indexOfHash( hash ) ),
cases[msg].storeItems[i].value,
msg + ': store item ' + i + ' found'
);
}
}
Preserve whitespace between elements This commit fully utilizes all four positions in the internal.whitespace array. Outer whitespace is now preserved as well, and is duplicated either in the adjacent sibling (one node's outerPost is the next sibling's outerPre) or in the parent (a branch node's innerPre is its first child's outerPre, and its innerPost is its last child's outerPost). Before restoring saved whitespace, we check that these two agree with each other, and if they disagree we assume the user has been moving stuff around and don't restore any whitespace in that spot. The whitespace at the very beginning and the very end of the document (i.e. the first node's outerPre and the last node's outerPost) isn't duplicated anywhere, nor is inner whitespace in content nodes. The basic outline of the implementation is: * When we encounter whitespace, strip it and store it in the previous node's outerPost. Also store it in nextWhitespace so we can put it in the next node's outerPre once we encounter that node. * When we encounter whitespace in wrapped bare text, we don't know in advance if it's gonna be succeeded by more non-whitespace (in which case it needs to be output verbatim), or not (in which case it's leading whitespace and needs to be stripped and stored). The fact that annotations are nodes in HTML makes this trickier. So we write the whitespace to the temporary linmod and store it in wrappedWhitespace, then if it turns out to be trailing whitespace we take it back out of the data array and record it the usual way. * Because text nodes can contain any combination of leading whitespace actual text and trailing whitespace, and because we may or may not already have opened a wrapping paragraph, there are a lot of different combinations to handle. We handle all of them but the resulting code is pretty dense and verbose. More low-level list of changes: In getDataFromDom(): * Added helper function addWhitespace() for storing whitespace for an element * Added helper function processNextWhitespace() for processing any whitespace passed on from the previous node via the nextWhitespace var * Rename paragraph to wrappingParagraph. Make wrapping default to alreadyWrapped so we can simplify wrapping||alreadyWrapped and !wrapping&&!alreadyWrapped. Add wrappingIsOurs to track whether the wrapping originated in this recursion level (needed for deciding when to close the wrapper). * Add prevElement to track the previous element so we can propagate whitespace to it, and nextWhitespace so we can propagate whitespace to the next element. * Remove previous newline stripping hacks * Integrate the logic for wrapping bare content with the outer whitespace preservation code * Remove wrapperElement, no longer needed because we have a dedicated variable for the wrapping paragraph now and what was previously inner whitespace preservation for wrapper paragraphs is now covered by the outer whitespace preservation code. In getDomFromData(): * Reinsert whitespace where appropriate ** outerPre is inserted when opening the element ** This covers outerPost as well except for the last child's outerPost, which is handled as the parent's innerPost when closing the parent. ** innerPre and innerPost are inserted when closing the element. Care is taken not to insert these if they're duplicates of something else. * Propagate each node's outerPost to the next node (either the next sibling or the parent) using parentDomElement.lastOuterPost. We can't get this using .lastChild because we will have destroyed that child's .veInternal by then, and we can't tell whether a node will be its parent's last child when we process it (all other processing, including first child handling is done when processing the node itself, but this cannot be). * Special handling is needed for the last node's outerPost, which ends up in the container's .lastOuterPost property. Tests: * Allow .html to be null in data<->DOM converter tests. This indicates that the test is a one-way data->DOM test, not a DOM->data->DOM round-trip test. The data will be converted to HTML and checked against .normalizedHtml * Update existing tests as needed * Add tests for outer whitespace preservation and storage * Add test for squashing of whitespace in case of disagreement (this requires .html=null) Change-Id: I4db4fe372a421182e80a2535657af7784ff15f95
2012-08-21 00:37:42 +00:00
}
}
} );
QUnit.test( 'getDomFromData', function ( assert ) {
var msg, originalData, doc, store, i, length, n = 0,
cases = ve.copyObject( ve.dm.example.domToDataCases );
for ( msg in cases ) {
n++;
}
QUnit.expect( 2*n );
Kranitor #1: On-boarding '''Kranitor commits''' are commits by Krinkle with his janitor hat on. Must never contain functional changes mixed with miscellaneous changes. .gitignore: * Add .DS_Store to the ignore list so that browsing the directories on Mac OS X, will not add these files to the list of untracked files. * Fix missing newline at end of file .jshintrc * raises -> throws * +module (QUnit.module) * remove 'Node' (as of node-jshint 1.7.2 this is now part of 'browser:true', as it should be) Authors: * Adding myself MWExtension/VisualEditor.php * Fix default value of wgVisualEditorParsoidURL to not point to the experimental instance in WMF Labs. Issues: * ve.ce.TextNode: - Fix TODO: Don't perform a useless clone of an already-jQuerified object. - Use .html() to set html content instead of encapsulating between two strings. This is slightly faster but more importantly safer, and prevents situations where the resulting jQuery collection actually contains 2 elements instead of 1, thus messing up what .contents() is iterating over. * ve.ce.Document.test.js - Fix: ReferenceError: assert is not defined * ve.dm.Document.test.js - Fix: ReferenceError: assert is not defined * ve.dm.Transaction.test.js - Fix: ReferenceError: assert is not defined * ve.dm.TransactionProcessor.test.js - Fix: ReferenceError: assert is not defined * ext.visualEditor.viewPageTarget - Missing dependency on 'mediawiki.Title' Code conventions / Misc cleanup * Various JSHint warnings. * Whitespace * jQuery(): Use '<tag>' for element creation, use '<valid><xml/></valid>' for parsing * Use the default operator instead of ternary when the condition and first value are the same. x = foo ? foo : bar; -> x = foo || bar; Because contrary to some programming language (PHP...), in JS the default operator does not enforce a boolean result but returns the original value, hence it being called the 'default' operator, as opposed to the 'or' operator. * No need to call addClass() twice, it takes a space-separated list (jQuery splits by space and adds if needed) * Use .on( event[, selector], fn ) instead of the deprecated routers to it such as .bind(), .delegate() and .live(). All these three are now built-in and fully compatible with .on() * Add 'XXX:' comments for suspicious code that I don't want to change as part of a clean up commit. * Remove unused variables (several var x = this; where x was not used anywhere, possibly from boilerplate copy/paste) * Follows-up Trevor's commit that converts test suites to the new QUnit format. Also removed the globals since we no longer use those any more. Change-Id: I7e37c9bff812e371c7f65a6fd85d9e2af3e0a22f
2012-07-27 08:43:33 +00:00
for ( msg in cases ) {
store = new ve.dm.IndexValueStore();
// load storeItems into store
if ( cases[msg].storeItems ) {
for ( i = 0, length = cases[msg].storeItems.length; i < length; i++ ) {
store.index( cases[msg].storeItems[i].value, cases[msg].storeItems[i].hash );
}
}
if ( cases[msg].modify ) {
cases[msg].modify( cases[msg].data );
}
doc = new ve.dm.Document( ve.dm.example.preprocessAnnotations( cases[msg].data, store ) );
originalData = ve.copyArray( doc.getFullData() );
assert.equalDomElement(
ve.dm.converter.getDomFromData( doc.getFullData(), doc.getStore(), doc.getInternalList() ),
ve.createDocumentFromHtml( cases[msg].normalizedHtml || cases[msg].html ),
msg
);
assert.deepEqualWithDomElements( doc.getFullData(), originalData, msg + ' (data hasn\'t changed)' );
}
} );