jenkins-bot has submitted this change and it was merged. (
https://gerrit.wikimedia.org/r/342024 )
Change subject: Use XPath to get text nodes for utterances.
......................................................................
Use XPath to get text nodes for utterances.
Replaced the index array paths with XPath expressions.
CleanedTag was also removed, since it's not needed anymore.
Bug: T158954
Change-Id: Ifec50d6d22a9e3e6adf51d96d315237852aa11ac
---
M extension.json
M includes/CleanedContent.php
M includes/Cleaner.php
M includes/HtmlGenerator.php
M includes/Segmenter.php
M modules/ext.wikispeech.css
M modules/ext.wikispeech.js
M tests/phpunit/CleanerTest.php
M tests/phpunit/HtmlGeneratorTest.php
M tests/phpunit/SegmenterTest.php
M tests/qunit/ext.wikispeech.test.js
11 files changed, 223 insertions(+), 731 deletions(-)
Approvals:
Lokal Profil: Looks good to me, approved
jenkins-bot: Verified
diff --git a/extension.json b/extension.json
index 0470c86..850c2b9 100644
--- a/extension.json
+++ b/extension.json
@@ -18,8 +18,6 @@
"AutoloadClasses": {
"SpecialWikispeech": "specials/SpecialWikispeech.php",
"WikispeechHooks": "Hooks.php",
- "CleanedContent": "includes/CleanedContent.php",
- "CleanedTag": "includes/CleanedContent.php",
"CleanedText": "includes/CleanedContent.php",
"Cleaner": "includes/Cleaner.php",
"HtmlGenerator": "includes/HtmlGenerator.php",
diff --git a/includes/CleanedContent.php b/includes/CleanedContent.php
index 3065afd..5042574 100644
--- a/includes/CleanedContent.php
+++ b/includes/CleanedContent.php
@@ -6,11 +6,9 @@
* @license GPL-2.0+
*/
-abstract class CleanedContent {
+class CleanedText {
/**
- * The string representation of the content, as it is written in
- * the HTML. This includes the tag name, any attributes, and the
- * brackets, if content is a tag.
+ * The text content from the text node this was created from.
*
* @var string $string
*/
@@ -18,25 +16,8 @@
public $string;
/**
- * Create a CleanedContent, given a string representation.
- *
- * @since 0.0.1
- * @param string $string The string representation of this content.
- */
-
- function __construct( $string ) {
- $this->string = $string;
- }
-}
-
-class CleanedTag extends CleanedContent {
-}
-
-class CleanedText extends CleanedContent {
- /**
- * The path in the HTML to the text node that this was created
- * from. The path consists of indices of the elements leading to
- * the text node, and the index of the text node itself.
+ * The XPath expression for the text node that this was created
+ * from.
*
* @var array $path
*/
@@ -46,15 +27,15 @@
/**
* Create a CleanedText, given a string representation.
*
- * If the path isn't set, it defaults to the empty array.
+ * If the path isn't set, it defaults to the empty string.
*
* @since 0.0.1
* @param string $string The string representation of this text.
* @param array $path The path to the text node this was created from.
*/
- function __construct( $string, $path=[] ) {
- parent::__construct( $string );
+ function __construct( $string, $path='' ) {
+ $this->string = $string;
$this->path = $path;
}
@@ -70,8 +51,7 @@
function toElement( $dom ) {
$element = $dom->createElement( 'text', $this->string );
- $pathString = implode( $this->path, ',' );
- $element->setAttribute( 'path', $pathString );
+ $element->setAttribute( 'path', $this->path );
return $element;
}
}
diff --git a/includes/Cleaner.php b/includes/Cleaner.php
index 1109d48..a65e0d6 100644
--- a/includes/Cleaner.php
+++ b/includes/Cleaner.php
@@ -16,25 +16,19 @@
* @since 0.0.1
* @param string $markedUpText Input text that may contain HTML
* tags.
- * @return array An array of nodes where tags are stored as
- * `CleanedTag`s and text nodes as `Text`.
+ * @return array An array of `CleanedText`s representing text nodes.
*/
public static function cleanHtml( $markedUpText ) {
$dom = self::createDomDocument( $markedUpText );
- $tags = self::getTags( $markedUpText );
- // Start adding the nodes that are children of the dummy
- // element. To not add the actual dummy tags, index starts on
- // -1.
- $tagIndex = -1;
+ $xpath = new DOMXPath( $dom );
+ // Only add elements below the dummy element. These are the
+ // elements from the original HTML.
+ $top = $xpath->evaluate( '/meta/dummy' )->item( 0 );
$cleanedContent = [];
self::addContent(
$cleanedContent,
- $dom->documentElement->firstChild,
- $markedUpText,
- $tags,
- $tagIndex,
- []
+ $top
);
return $cleanedContent;
}
@@ -66,296 +60,38 @@
}
/**
- * Extract a list of tags from a string.
+ * Recursively add content as `CleanedText`s.
*
- * Tags are extracted in the order they appear. This is done using
- * regex since we need the exact string representation of tags to
- * get their correct lengths.
- *
- * When a start tag is encountered, it's stored as a string. This
- * string is then added to an array, which holds a start-end pair
- * of tags.
- *
- * When an end tag is encountered, it's stored as a string. This
- * string is then added to the array containing the corresponding
- * start tag.
- *
- * Empty element tags are added as tag strings.
+ * Goes through all the child nodes of $node and adds their content
text.
*
* @since 0.0.1
- * @param string $markedUpText The string to extract tags from.
- * @return array An array containing the found tags.
- */
-
- private static function getTags( $markedUpText ) {
- $potentialTagBrackets = [];
- preg_match_all(
- '/[<>]/',
- $markedUpText,
- $potentialTagBrackets,
- PREG_SET_ORDER | PREG_OFFSET_CAPTURE
- );
- $tags = [];
- $startBracket = null;
- foreach ( $potentialTagBrackets as $match ) {
- // $match[0] is an array containing the matched string
and it's
- // position.
- $bracketString = $match[0][0];
- if ( $bracketString == '<' ) {
- if ( $startBracket == null ) {
- $startBracket = $match[0];
- }
- } elseif ( $bracketString == '>' && $startBracket !=
null ) {
- $tagString = substr(
- $markedUpText,
- $startBracket[1],
- $match[0][1] - $startBracket[1] + 1
- );
- $startBracket = null;
- if ( self::isStartTag( $tagString ) ) {
- array_push( $tags, [ $tagString ] );
- } elseif ( self::isEndTag( $tagString ) ) {
- $startTagIndex =
self::getCorrespondingStartTagIndex(
- $tags,
- $tagString
- );
- // Add the end tag to the array already
containing the
- // start tag.
- array_push(
- $tags[$startTagIndex],
- $tagString
- );
- } elseif ( self::isEmptyElementTag( $tagString
) ) {
- array_push( $tags, $tagString );
- }
- }
- }
- return $tags;
- }
-
- /**
- * Test if a string is a start tag.
- *
- * @since 0.0.1
- * @param $tagString The string to test.
- * @return true if $tagString is a start tag, else false.
- */
-
- private static function isStartTag( $tagString ) {
- return substr( $tagString, 0, 2 ) != '</' &&
- substr( $tagString, -2 ) != '/>';
- }
-
- /**
- * Test if a string is an end tag.
- *
- * @since 0.0.1
- * @param $tagString The string to test.
- * @return true if $tagString is an end tag, else false.
- */
-
- private static function isEndTag( $tagString ) {
- return substr( $tagString, 0, 2 ) == '</';
- }
-
- /**
- * Test if a string is an empty element tag.
- *
- * @since 0.0.1
- * @param $tagString The string to test.
- * @return true if $tagString is an empty element tag, else false.
- */
-
- private static function isEmptyElementTag( $tagString ) {
- return substr( $tagString, -2 ) == '/>';
- }
-
- /**
- * Get the index in $tags of the tag that starts the element which
- * ends with $tagString.
- *
- * Traverses $tags backwards and tests if start tags are of the
- * same type as the one in $tagString.
- *
- * @since 0.0.1
- * @param array $tags Tag array, as returned from getTags().
- * @param string $tagString the end tag to find start tag for, as
- * HTML string.
- * @return int The index in $tags of the start tag found.
- */
-
- private static function getCorrespondingStartTagIndex(
- $tags,
- $tagString
- ) {
- for ( $i = count( $tags ) - 1; $i >= 0; $i -- ) {
- $tag = $tags[$i];
- if ( is_array( $tag ) && count( $tag ) == 1 ) {
- // Make sure the tag to test is an array, i.e.
a start
- // tag, and that it doesn't have an end tag
already.
- $startTagType = self::getTagName( $tag[0] );
- $endTagType = self::getTagName( $tagString );
- if ( $startTagType == $endTagType ) {
- return $i;
- }
- }
- }
- }
-
- /**
- * Get the tag name from a tag string.
- *
- * @since 0.0.1
- * @param string $tagString The tag as string.
- * @return string The name of the tag in $tagString.
- */
-
- private static function getTagName( $tagString ) {
- $nameMatch = null;
- preg_match( '!</?([^ />]+)( />)?!', $tagString, $nameMatch );
- $tagName = $nameMatch[1];
- return $tagName;
- }
-
- /**
- * Recursively add content as either CleanedTags or strings.
- *
- * Goes through all the child nodes of $node and adds the
- * corresponding content. If a child is a tag, it's added as a
- * CleanedTag of the appropriate type (Start, End or Empty). If a
- * child is a text node, the text is added as a string.
- *
- * @since 0.0.1
- * @param array $content The resulting array of CleanedTags and
- * strings.
+ * @param array $content The resulting array of `CleanedText`s.
* @param DOMNode $node The top node to add from.
- * @param string $source The HTML string that DOM is generated
- * from. Used for retrieveing element contents.
- * @param array $tags Tag array, as generated by getTags().
- * @param int $tagIndex The index of the next tag, from $tags.
- * @param array $path The indices of each ancestor node to
- * $node. Used for connecting a Text element to a text node in
- * the HTML.
*/
private static function addContent(
&$content,
- $node,
- $source,
- $tags,
- &$tagIndex,
- $path
+ $node
) {
- $startTag = null;
- $endTag = null;
- if ( $tagIndex >= 0 ) {
- // Don't add the dummy tag.
- if ( is_array( $tags[$tagIndex] ) ) {
- // If an item in $tags is an array, it holds
arrays
- // for start and end tags.
- $startTag = $tags[$tagIndex][0];
- $endTag = $tags[$tagIndex][1];
- array_push( $content, new CleanedTag( $startTag
) );
- } else {
- // If the tag is empty, just add it and return,
since
- // there can't be any child nodes.
- $emptyElementTagString = $tags[$tagIndex];
- array_push(
- $content,
- new CleanedTag( $emptyElementTagString )
- );
- return;
+ if ( !self::matchesRemove( $node ) ) {
+ foreach ( $node->childNodes as $child ) {
+ if ( $child->nodeType == XML_TEXT_NODE ) {
+ // Remove the path to the dummy node
and instead add
+ // "." to match when used with context.
+ $path = preg_replace(
+ '!^/meta/dummy!',
+ '.',
+ $child->getNodePath()
+ );
+ $text = new CleanedText(
$child->textContent, $path );
+ array_push( $content, $text );
+ } else {
+ self::addContent(
+ $content,
+ $child
+ );
+ }
}
- }
- if ( self::matchesRemove( $node ) ) {
- // When a tag is removed, skip forward a number of tags
- // equal to the number of nodes under that tag.
- $tagIndex += self::getNumberOfDescendants( $node );
- } else {
- self::addChildren(
- $content,
- $node,
- $source,
- $tags,
- $tagIndex,
- $path
- );
- }
- if ( $endTag != null ) {
- array_push(
- $content,
- new CleanedTag( $endTag )
- );
- }
- }
-
- /**
- * Get the number of nodes that are descendants of a given node.
- *
- * @since 0.0.1
- * @param DOMNode $node The node to get number of descendants of.
- * @return int The number of decendants of $node.
- */
-
- private static function getNumberOfDescendants( $node ) {
- if ( !$node->hasChildNodes() ) {
- return 0;
- }
- $numberOfDescendants = 0;
- foreach ( $node->childNodes as $child ) {
- if ( $child->nodeType != XML_TEXT_NODE ) {
- $numberOfDescendants +=
- 1 + self::getNumberOfDescendants(
$child );
- }
- }
- return $numberOfDescendants;
- }
-
- /**
- * Add content for child nodes to an array.
- *
- * @since 0.0.1
- * @param array $content The array that the children are added to.
- * @param DOMNode $node Add content for the children of this node.
- * @param string $source The HTML string that DOM is generated
- * from. Used for retrieveing element contents.
- * @param array $tags Tag array, as generated by getTags().
- * @param int $tagIndex The index of the next tag, from $tags.
- * @param array $path The indices of each ancestor node to
- * $node. Used for connecting a Text element to a text node in
- * the HTML.
- */
-
- private static function addChildren(
- &$content,
- $node,
- $source,
- $tags,
- &$tagIndex,
- $path
- ) {
- $childIndex = 0;
- foreach ( $node->childNodes as $child ) {
- $childPath = $path;
- array_push( $childPath, $childIndex );
- if ( $child->nodeType == XML_TEXT_NODE ) {
- $text = new CleanedText( $child->textContent,
$childPath );
- array_push( $content, $text );
- } else {
- // Nodes are handled even if their parents are
- // removed, to not get the DOM nodes out of
sync with
- // $tags.
- $tagIndex += 1;
- self::addContent(
- $content,
- $child,
- $source,
- $tags,
- $tagIndex,
- $childPath
- );
- }
- $childIndex ++;
}
}
diff --git a/includes/HtmlGenerator.php b/includes/HtmlGenerator.php
index 649010e..136631a 100644
--- a/includes/HtmlGenerator.php
+++ b/includes/HtmlGenerator.php
@@ -62,7 +62,9 @@
* The element looks like this in HTML:
* <utterance id="utterance-0>
* <content>
- * Utterance string with <cleaned-tag>not removed tag</cleaned-tag>.
+ * <text>Utterance with</text>
+ * <text>tag</text>
+ * <text>.</text>
* </content>
* </utterance>
*
@@ -70,16 +72,13 @@
* utterances, when next or previous utterance should be played.
*
* The content element contains a representation of the HTML that
- * was used to generate this utterance. Text nodes are the same as
- * in the original HTML. Elements are represented by cleaned-tag
- * elements, whose contents are the tags from the original HTML,
- * excluding < and >.
+ * was used to generate this utterance. Text nodes are represented
+ * by `<text>` elements.
*
* @since 0.0.1
* @param DOMDocument $dom The DOMDocument to use for creating the
* element.
- * @param array $segment An array with position and content as an
- * array of CleanedTags and strings.
+ * @param array $segment An array of `CleanedText`s.
* @param int $index The index of the element, used for giving it
* an id. Later used for playing the utterances in the correct
* order.
@@ -108,26 +107,17 @@
/**
* Create a content element from a content array.
*
- * CleanedTags are represented as cleaned-tag elements, strings as
- * text nodes.
+ * `CleanedText`s are represented by `<text>` nodes.
*
* @since 0.0.1
- * @param array $content An array of CleanedTags and strings.
+ * @param array $content An array of `CleanedText`s.
* @return DOMNode A content element.
*/
private static function createContentElement( $dom, $content ) {
$contentElement = $dom->createElement( 'content' );
foreach ( $content as $part ) {
- if ( $part instanceof CleanedTag ) {
- // Remove the < and > from the tag string to
not have to
- // decode them later.
- $text = substr( $part->string, 1, -1 );
- $cleanedTagElement = $dom->createElement(
'cleaned-tag', $text );
- $contentElement->appendChild(
$cleanedTagElement );
- } else {
$contentElement->appendChild( $part->toElement(
$dom ) );
- }
}
return $contentElement;
}
diff --git a/includes/Segmenter.php b/includes/Segmenter.php
index 8eba68c..249bbf5 100644
--- a/includes/Segmenter.php
+++ b/includes/Segmenter.php
@@ -12,7 +12,7 @@
* Divide a cleaned content array into segments, one for each sentence.
*
* A segment is an array with the keys "content", "startOffset"
- * and "endOffset". "content" is an array of `CleanedContent`s.
+ * and "endOffset". "content" is an array of `CleanedText`s.
* "startOffset" is the position of the first character of the
* segment, within the text node it appears. "endOffset" is the
@@ -24,10 +24,10 @@
* dot (full stop). Headings are also considered sentences.
*
* @since 0.0.1
- * @param array $cleanedContent An array of `CleanedContent`s, as
+ * @param array $cleanedContent An array of `CleanedText`s, as
* returned by `Cleaner::cleanHtml()`.
* @return array An array of segments, each containing the
- * `CleanedContent's in that segment.
+ * `CleanedText's in that segment.
*/
public static function segmentSentences( $cleanedContent ) {
@@ -37,17 +37,11 @@
'startOffset' => 0
];
foreach ( $cleanedContent as $content ) {
- if ( $content instanceof CleanedTag ) {
- // Non-text nodes are always added to the
current segment, as
- // they can't contain segment breaks.
- array_push( $currentSegment['content'],
$content );
- } else {
- self::addSegments(
- $segments,
- $currentSegment,
- $content
- );
- }
+ self::addSegments(
+ $segments,
+ $currentSegment,
+ $content
+ );
}
if ( $currentSegment['content'] ) {
// Add the last segment, unless it's empty.
diff --git a/modules/ext.wikispeech.css b/modules/ext.wikispeech.css
index 7d27ba7..98d0148 100644
--- a/modules/ext.wikispeech.css
+++ b/modules/ext.wikispeech.css
@@ -32,11 +32,6 @@
content: '\f050';
}
-.ext-wikispeech-highlight-sentence {
- background-color: rgb( 0, 200, 0 );
- background-color: rgba( 0, 200, 0, 0.5 );
-}
-
.ext-wikispeech-control-panel {
position: fixed;
left: 0;
@@ -46,3 +41,8 @@
border: solid 1px rgb( 150, 150, 150 );
background-color: rgb( 200, 200, 200 );
}
+
+.ext-wikispeech-highlight-sentence {
+ background-color: rgb( 0, 200, 0 );
+ background-color: rgba( 0, 200, 0, 0.5 );
+}
diff --git a/modules/ext.wikispeech.js b/modules/ext.wikispeech.js
index 4290182..8423a4a 100644
--- a/modules/ext.wikispeech.js
+++ b/modules/ext.wikispeech.js
@@ -189,59 +189,58 @@
this.highlightUtterance = function ( $utterance ) {
var firstTextElement, firstNode, lastTextElement,
lastNode,
- firstNodeRange, startOffset, endOffset,
textNode;
+ startOffset, endOffset, textNode, middleNodes;
firstTextElement = $utterance.find( 'text' ).get( 0 );
if ( firstTextElement ) {
firstNode = self.getNodeForTextElement(
firstTextElement );
lastTextElement = $utterance.find( 'text'
).get( -1 );
lastNode = self.getNodeForTextElement(
lastTextElement );
-
- // Range for the first node, since it may be
that only
- // part of this should be highlighted.
- firstNodeRange = document.createRange();
startOffset =
parseInt( $utterance.attr(
'start-offset' ), 10 );
- firstNodeRange.setStart( firstNode, startOffset
);
endOffset =
parseInt( $utterance.attr( 'end-offset'
), 10 );
if ( firstNode === lastNode ) {
- // All highlighted text is in the same
text node, so
- // only a range is needed.
- firstNodeRange.setEnd( firstNode,
endOffset + 1 );
- } else {
- // Since the highlighting extends
beyond the first
- // text node, all text from the start
position should
- // be highlighted.
- firstNodeRange.setEnd(
+ // All highlighted text is in the same
text node,
+ // so only one <span> is needed.
+ self.highlightRange(
firstNode,
- firstNode.textContent.length
+ startOffset,
+ endOffset
);
- // Add highlighting by range for the
last text
- // node, since it may be that the
highlighting
- // doesn't cover the whole node.
- self.highlightRange( lastNode, 0,
endOffset + 1 );
-
+ } else {
+ // The middle nodes need to be found
before the
+ // other highlighting, since adding
<span>s
+ // changes how the XPath expressions are
+ // interpreted.
+ middleNodes = [];
$utterance.find( 'text:gt(0):lt(-1)'
).each( function () {
- // Add highlighting to all text
nodes between
- // first and last node.
textNode =
self.getNodeForTextElement( this );
- $( textNode ).wrap(
+ middleNodes.push( textNode );
+ } );
+
+ // Add a <span> around the part of the
last node
+ // that is part if the utterance.
+ self.highlightRange( lastNode, 0,
endOffset );
+ // Wrap all nodes between the first and
last
+ // completely in <span>s.
+ middleNodes.forEach( function ( node ) {
+ $( node ).wrap(
self.createHighilightUtteranceSpan()
);
} );
+ // Add a <span> around the part of the
first node
+ // that is part if the utterance.
+ self.highlightRange( firstNode,
startOffset );
}
- firstNodeRange.surroundContents(
- self.createHighilightUtteranceSpan()
- );
}
};
/**
* Find the text node from which a `<text>` element was created.
*
- * The path attribute of textElement is used to traverse the
- * DOM tree.
+ * The path attribute of textElement is an XPath expression
+ * and is used to traverse the DOM tree.
*
* @param {HTMLElement} textElement The `<text>` element to find
* the text node for.
@@ -249,11 +248,19 @@
*/
this.getNodeForTextElement = function ( textElement ) {
- var path, node;
+ var path, node, result;
- path = textElement.getAttribute( 'path' ).split( ',' );
- node =
- self.getNodeFromPath( path, $(
'#mw-content-text' ).get( 0 ) );
+ path = textElement.getAttribute( 'path' );
+ // The path should be unambiguous, so just get the first
+ // matching node.
+ result = document.evaluate(
+ path,
+ $( '#mw-content-text' ).get( 0 ),
+ null,
+ XPathResult.FIRST_ORDERED_NODE_TYPE,
+ null
+ );
+ node = result.singleNodeValue;
return node;
};
@@ -286,13 +293,17 @@
* @param {number} start The index of the first character in the
* highlighting.
* @param {number} end The index of the last character in the
- * highlighting.
+ * highlighting. If not specified, the last character in the
+ * text node is used.
*/
this.highlightRange = function ( node, start, end ) {
var range = document.createRange();
range.setStart( node, start );
- range.setEnd( node, end );
+ if ( end === undefined ) {
+ end = node.textContent.length - 1;
+ }
+ range.setEnd( node, end + 1 );
range.surroundContents(
self.createHighilightUtteranceSpan() );
};
@@ -730,7 +741,7 @@
* The request should specify the following parameters:
* - lang: the language used by the synthesizer.
* - input_type: "ssml" if you want SSML markup, otherwise
- * "text" for plain text.
+ * "text" for plain text.
* - input: the text to be synthesized.
* For more on the parameters, see:
* https://github.com/stts-se/wikispeech_mockup/wiki/api.
diff --git a/tests/phpunit/CleanerTest.php b/tests/phpunit/CleanerTest.php
index 31615e5..0303ef4 100644
--- a/tests/phpunit/CleanerTest.php
+++ b/tests/phpunit/CleanerTest.php
@@ -25,9 +25,7 @@
public function testCleanTags() {
$markedUpText = '<i>Element content</i>';
$expectedCleanedContent = [
- new CleanedTag( '<i>' ),
- new CleanedText( 'Element content' ),
- new CleanedTag( '</i>' )
+ new CleanedText( 'Element content' )
];
$this->assertTextCleaned( $expectedCleanedContent,
$markedUpText );
}
@@ -105,9 +103,8 @@
* Assert correct output when input is preceded and followed by text.
*
* Pre- and suffix strings are concatenated to the first and last
- * part respectively, of the expected content if they are
- * `Text`s. If they are `CleanedTag`s, they are added as new
- * parts.
+ * `CleanedText` respectively, unless there are tags in the marked
+ * up text. In that case, new `CleanedText`s are added.
*
* @since 0.0.1
* @param array $expectedCleanedContents The content array that is
@@ -120,20 +117,30 @@
$expectedCleanedContents,
$markedUpText
) {
- if ( is_a( $expectedCleanedContents[0], 'CleanedText' ) ) {
+ if ( $markedUpText[0] == '<' ) {
+ array_unshift(
+ $expectedCleanedContents,
+ new CleanedText( 'prefix' )
+ );
+ } else {
$expectedCleanedContents[0] =
- new CleanedText( 'prefix' .
$expectedCleanedContents[0]->string );
- } else {
- array_unshift( $expectedCleanedContents, new
CleanedText( 'prefix' ) );
- }
- $lastIndex = count( $expectedCleanedContents ) - 1;
- if ( is_a( $expectedCleanedContents[$lastIndex], 'CleanedText'
) ) {
- $expectedCleanedContents[$lastIndex] =
new CleanedText(
-
$expectedCleanedContents[$lastIndex]->string . 'suffix'
+ 'prefix' .
$expectedCleanedContents[0]->string
);
+ }
+ $lastCharIndex = mb_strlen( $markedUpText ) - 1;
+ if ( $markedUpText[$lastCharIndex] == '>' ) {
+ array_push(
+ $expectedCleanedContents,
+ new CleanedText( 'suffix' )
+ );
} else {
- array_push( $expectedCleanedContents, new CleanedText(
'suffix' ) );
+ $lastContentIndex = count( $expectedCleanedContents ) -
1;
+ $expectedCleanedContents[$lastContentIndex] =
+ new CleanedText(
+
$expectedCleanedContents[$lastContentIndex]->string
+ . 'suffix'
+ );
}
$this->assertContentsEqual(
$expectedCleanedContents,
@@ -144,12 +151,11 @@
/**
* Assert correct output when input is repeated and separated by string.
*
- * If the first instance of the expected content ends with a
- * `Text`, the infix is added after that. If the second instance
- * starts with a `Text`, the infix is added before that. If both
- * cases occur at the same time, the `Text` between the instances
- * will consist of the last `Text` of first instance, infix and
- * first `Text` of second instance.
+ * Adds the infix as a `CleanedText` between two copies of
+ * $expectedCleanedContents. If the marked up text doesn't end
+ * with a tag, the infix is added to the end of the first
+ * copy. Similarily, it's added to the beginning if the marked up
+ * text doesn't start with a tag.
*
* @since 0.0.1
* @param array $expectedCleanedContents The content array that
@@ -164,13 +170,13 @@
) {
$infix = new CleanedText( 'infix' );
$firstContents = $expectedCleanedContents;
- $lastIndex = count( $firstContents ) - 1;
- if ( is_a( $firstContents[$lastIndex], 'CleanedText' ) ) {
+ $lastCharIndex = mb_strlen( $markedUpText ) - 1;
+ if ( $markedUpText[$lastCharIndex] != '>' ) {
$adjacent = array_pop( $firstContents );
$infix->string = $adjacent->string . $infix->string;
}
$secondContents = $expectedCleanedContents;
- if ( is_a( $secondContents[0], 'CleanedText' ) ) {
+ if ( $markedUpText[0] != '<' ) {
$adjacent = array_shift( $secondContents );
$infix->string .= $adjacent->string;
}
@@ -194,69 +200,42 @@
public function testCleanNestedTags() {
$markedUpText = '<i><b>Nested content</b></i>';
$expectedCleanedContent = [
- new CleanedTag( '<i>' ),
- new CleanedTag( '<b>' ),
- new CleanedText( 'Nested content' ),
- new CleanedTag( '</b>' ),
- new CleanedTag( '</i>' )
+ new CleanedText( 'Nested content' )
];
$this->assertTextCleaned( $expectedCleanedContent,
$markedUpText );
}
public function testCleanEmptyElementTags() {
$markedUpText = '<br />';
- $expectedCleanedContent = [
- new CleanedTag( '<br />' )
- ];
- $this->assertTextCleaned( $expectedCleanedContent,
$markedUpText );
+ $this->assertTextCleaned( [], $markedUpText );
}
public function testRemoveTags() {
$markedUpText = '<del>removed tag </del>';
- $expectedCleanedContent = [
- new CleanedTag( '<del>' ),
- new CleanedTag( '</del>' )
- ];
- $this->assertTextCleaned( $expectedCleanedContent,
$markedUpText );
+ $this->assertTextCleaned( [], $markedUpText );
}
- public function testDontAddCleanedTagsForTagsUnderRemovedTags() {
+ public function testRemoveNestedTags() {
$markedUpText = '<del><i>nested removed tag</i></del>';
- $expectedCleanedContent = [
- new CleanedTag( '<del>' ),
- new CleanedTag( '</del>' )
- ];
- $this->assertTextCleaned( $expectedCleanedContent,
$markedUpText );
+ $this->assertTextCleaned( [], $markedUpText );
}
public function testRemoveDoubleNestedTags() {
$markedUpText = '<del><i><b>double nested removed
tag</b></i></del>';
- $expectedCleanedContent = [
- new CleanedTag( '<del>' ),
- new CleanedTag( '</del>' )
- ];
- $this->assertTextCleaned( $expectedCleanedContent,
$markedUpText );
+ $this->assertTextCleaned( [], $markedUpText );
}
public function testRemoveTagsWithCertainClass() {
$markedUpText = '<sup class="reference">Remove this.</sup>';
- $expectedCleanedContent = [
- new CleanedTag( '<sup class="reference">' ),
- new CleanedTag( '</sup>' )
- ];
- $this->assertTextCleaned( $expectedCleanedContent,
$markedUpText );
+ $this->assertTextCleaned( [], $markedUpText );
}
public function testDontRemoveTagsWithoutCertainClass() {
$markedUpText =
'<sup>I am not a reference.</sup><sup
class="not-a-reference">Neither am I.</sup>';
$expectedCleanedContent = [
- new CleanedTag( '<sup>' ),
new CleanedText( 'I am not a reference.' ),
- new CleanedTag( '</sup>' ),
- new CleanedTag( '<sup class="not-a-reference">' ),
- new CleanedText( 'Neither am I.' ),
- new CleanedTag( '</sup>' )
+ new CleanedText( 'Neither am I.' )
];
$this->assertTextCleaned( $expectedCleanedContent,
$markedUpText );
}
@@ -264,9 +243,7 @@
public function testDontRemoveTagsWhoseCriteriaAreFalse() {
$markedUpText = '<h2>Contents</h2>';
$expectedCleanedContent = [
- new CleanedTag( '<h2>' ),
- new CleanedText( 'Contents' ),
- new CleanedTag( '</h2>' )
+ new CleanedText( 'Contents' )
];
$this->assertTextCleaned( $expectedCleanedContent,
$markedUpText );
}
@@ -274,23 +251,13 @@
public function testHandleMultipleClasses() {
$markedUpText =
'<sup class="reference another-class">Remove
this.</sup>';
- $expectedCleanedContent = [
- new CleanedTag( '<sup class="reference another-class">'
),
- new CleanedTag( '</sup>' )
- ];
- $this->assertTextCleaned( $expectedCleanedContent,
$markedUpText );
+ $this->assertTextCleaned( [], $markedUpText );
}
public function testCleanNestedTagsWhereSomeAreRemovedAndSomeAreKept() {
$markedUpText = '<i><b>not removed</b><del>removed</del></i>';
$expectedCleanedContent = [
- new CleanedTag( '<i>' ),
- new CleanedTag( '<b>' ),
- new CleanedText( 'not removed' ),
- new CleanedTag( '</b>' ),
- new CleanedTag( '<del>' ),
- new CleanedTag( '</del>' ),
- new CleanedTag( '</i>' )
+ new CleanedText( 'not removed' )
];
$this->assertTextCleaned( $expectedCleanedContent,
$markedUpText );
}
@@ -310,9 +277,7 @@
public function testHandleNewlines() {
$markedUpText = "<i>Keep this newline\n</i>";
$expectedCleanedContent = [
- new CleanedTag( '<i>' ),
- new CleanedText( "Keep this newline\n" ),
- new CleanedTag( '</i>' )
+ new CleanedText( "Keep this newline\n" )
];
$this->assertTextCleaned( $expectedCleanedContent,
$markedUpText );
}
@@ -320,10 +285,7 @@
public function testHandleEndTagFollowedByEmptyElementTag() {
$markedUpText = '<i>content</i><br />';
$expectedCleanedContent = [
- new CleanedTag( '<i>' ),
- new CleanedText( 'content' ),
- new CleanedTag( '</i>' ),
- new CleanedTag( '<br />' )
+ new CleanedText( 'content' )
];
$this->assertTextCleaned( $expectedCleanedContent,
$markedUpText );
}
@@ -331,10 +293,7 @@
public function testHandleEmptyElementTagInsideElement() {
$markedUpText = '<i>content<br /></i>';
$expectedCleanedContent = [
- new CleanedTag( '<i>' ),
- new CleanedText( 'content' ),
- new CleanedTag( '<br />' ),
- new CleanedTag( '</i>' )
+ new CleanedText( 'content' )
];
$this->assertTextCleaned( $expectedCleanedContent,
$markedUpText );
}
@@ -342,14 +301,9 @@
public function testGeneratePaths() {
$markedUpText = '<i>level one<br /><b>level two</b></i>level
zero';
$expectedCleanedContent = [
- new CleanedTag( '<i>' ),
- new CleanedText( 'level one', [ 0, 0 ] ),
- new CleanedTag( '<br />' ),
- new CleanedTag( '<b>' ),
- new CleanedText( 'level two', [ 0, 2, 0 ] ),
- new CleanedTag( '</b>' ),
- new CleanedTag( '</i>' ),
- new CleanedText( 'level zero', [ 1 ] )
+ new CleanedText( 'level one', './i/text()' ),
+ new CleanedText( 'level two', './i/b/text()' ),
+ new CleanedText( 'level zero', './text()' )
];
$this->assertEquals(
$expectedCleanedContent,
@@ -360,12 +314,8 @@
public function testGeneratePathsNestedOfSameType() {
$markedUpText = '<i id="1">one<i id="2">two</i></i>';
$expectedCleanedContent = [
- new CleanedTag( '<i id="1">' ),
- new CleanedText( 'one', [ 0, 0 ] ),
- new CleanedTag( '<i id="2">' ),
- new CleanedText( 'two', [ 0, 1, 0 ] ),
- new CleanedTag( '</i>' ),
- new CleanedTag( '</i>' )
+ new CleanedText( 'one', './i/text()' ),
+ new CleanedText( 'two', './i/i/text()' )
];
$this->assertEquals(
$expectedCleanedContent,
@@ -373,69 +323,15 @@
);
}
- public function testGetTags() {
- $textWithTags = '<i>content</i>';
- $expectedTags = [ [
- '<i>',
- '</i>'
- ] ];
- $this->assertEquals(
- $expectedTags,
- Util::call( 'Cleaner', 'getTags', $textWithTags )
- );
- }
-
- public function testGetTagsEmptyElementTag() {
- $textWithTags = '<br />';
- $expectedTags = [ '<br />' ];
- $this->assertEquals(
- $expectedTags,
- Util::call( 'Cleaner', 'getTags', $textWithTags )
- );
- }
-
- public function testGetTagsEmptyElementTagWithoutSpace() {
- $textWithTags = '<br/>';
- $expectedTags = [ '<br/>' ];
- $this->assertEquals(
- $expectedTags,
- Util::call( 'Cleaner', 'getTags', $textWithTags )
- );
- }
-
- public function testGetTagsNestedTags() {
- $textWithTags = '<i>content<b>content</b></i>';
- $expectedTags = [
- [
- '<i>',
- '</i>'
- ],
- [
- '<b>',
- '</b>'
- ]
+ public function testGeneratePathsNodesOnSameLevel() {
+ $markedUpText = 'level zero<br />also level zero';
+ $expectedCleanedContent = [
+ new CleanedText( 'level zero', './text()[1]' ),
+ new CleanedText( 'also level zero', './text()[2]' )
];
$this->assertEquals(
- $expectedTags,
- Util::call( 'Cleaner', 'getTags', $textWithTags )
- );
- }
-
- public function testGetTagsNestedTagsOfSameType() {
- $textWithTags = '<i id="1">content<i id="2">content</i></i>';
- $expectedTags = [
- [
- '<i id="1">',
- '</i>'
- ],
- [
- '<i id="2">',
- '</i>'
- ]
- ];
- $this->assertEquals(
- $expectedTags,
- Util::call( 'Cleaner', 'getTags', $textWithTags )
+ $expectedCleanedContent,
+ Cleaner::cleanHtml( $markedUpText )
);
}
}
diff --git a/tests/phpunit/HtmlGeneratorTest.php
b/tests/phpunit/HtmlGeneratorTest.php
index c2d6a97..1008454 100644
--- a/tests/phpunit/HtmlGeneratorTest.php
+++ b/tests/phpunit/HtmlGeneratorTest.php
@@ -14,7 +14,7 @@
$segment = [
'startOffset' => 0,
'endOffset' => 12,
- 'content' => [ new CleanedText( 'An utterance.', [ 0, 1
] ) ],
+ 'content' => [ new CleanedText( 'An utterance.',
'/p/text()' ) ]
];
$utteranceElement = Util::call(
'HtmlGenerator',
@@ -42,7 +42,10 @@
$textElement = $xpath->query( '/utterance/content/text'
)->item( 0 );
$this->assertEquals( 'text', $textElement->nodeName );
$this->assertEquals( 'An utterance.', $textElement->nodeValue );
- $this->assertEquals( '0,1', $textElement->getAttribute( 'path'
) );
+ $this->assertEquals(
+ '/p/text()',
+ $textElement->getAttribute( 'path' )
+ );
}
/**
@@ -63,7 +66,7 @@
$segment = [
'startOffset' => null,
'endOffset' => null,
- 'content' => [ new CleanedText( 'This is #1.', [] ) ]
+ 'content' => [ new CleanedText( 'This is #1.' ) ]
];
$utteranceElement = Util::call(
'HtmlGenerator',
@@ -81,7 +84,7 @@
$segment = [
'startOffset' => null,
'endOffset' => null,
- 'content' => [ new CleanedText( 'This is not really a
<tag>.', [] ) ]
+ 'content' => [ new CleanedText( 'This is not really a
<tag>.' ) ]
];
$utteranceElement = Util::call(
'HtmlGenerator',
@@ -114,12 +117,12 @@
[
'startOffset' => null,
'endOffset' => null,
- 'content' => [ new CleanedText( 'Sentence 1.',
[] ) ]
+ 'content' => [ new CleanedText( 'Sentence 1.' )
]
],
[
'startOffset' => null,
'endOffset' => null,
- 'content' => [ new CleanedText( ' Sentence 2.',
[] ) ]
+ 'content' => [ new CleanedText( ' Sentence 2.'
) ]
]
];
$utterancesElement = Util::call(
@@ -132,53 +135,5 @@
$utterancesElement->getElementsByTagName( 'utterance' );
$this->assertEquals( 2, $utteranceElements->length );
$this->assertTrue( $utterancesElement->hasAttribute( 'hidden' )
);
- }
-
- public function testCreateUtterancesContainingCleanedTags() {
- $segment = [
- 'startOffset' => null,
- 'endOffset' => null,
- 'content' => [
- new CleanedText( 'Here is a ', [] ),
- new CleanedTag( '<i>' ),
- new CleanedText( 'tag', [] ),
- new CleanedTag( '</i>', [] )
- ]
- ];
- $utteranceElement = Util::call(
- 'HtmlGenerator',
- 'createUtteranceElement',
- new DOMDocument(),
- $segment,
- 0
- );
- $xpath = self::getXpath( $utteranceElement );
- $contentChildren = $xpath->evaluate( '/utterance/content/*' );
- $this->assertEquals( 'text', $contentChildren->item( 0
)->nodeName );
- $this->assertEquals(
- 'Here is a ',
- $contentChildren->item( 0 )->nodeValue
- );
- $this->assertEquals(
- 'cleaned-tag',
- $contentChildren->item( 1 )->nodeName
- );
- $this->assertEquals(
- 'i',
- $contentChildren->item( 1 )->nodeValue
- );
- $this->assertEquals( 'text', $contentChildren->item( 2
)->nodeName );
- $this->assertEquals(
- 'tag',
- $contentChildren->item( 2 )->nodeValue
- );
- $this->assertEquals(
- 'cleaned-tag',
- $contentChildren->item( 3 )->nodeName
- );
- $this->assertEquals(
- '/i',
- $contentChildren->item( 3 )->nodeValue
- );
}
}
diff --git a/tests/phpunit/SegmenterTest.php b/tests/phpunit/SegmenterTest.php
index 3496794..09800d0 100644
--- a/tests/phpunit/SegmenterTest.php
+++ b/tests/phpunit/SegmenterTest.php
@@ -78,44 +78,6 @@
$this->assertEquals( 27, $segments[1]['endOffset'] );
}
- public function testSegmentContainingTag() {
- $cleanedContent = [
- new CleanedText( 'Sentence with a ' ),
- new CleanedTag( '<i>' ),
- new CleanedText( 'tag' ),
- new CleanedTag( '</i>' ),
- new CleanedText( '.' )
- ];
- $expectedContent = [
- new CleanedText( 'Sentence with a ' ),
- new CleanedTag( '<i>' ),
- new CleanedText( 'tag' ),
- new CleanedTag( '</i>' ),
- new CleanedText( '.' )
- ];
- $segments = Segmenter::segmentSentences( $cleanedContent );
- $this->assertEquals(
- $expectedContent,
- $segments[0]['content']
- );
- }
-
- public function testSegmentEndingWithTag() {
- $cleanedContent = [
- new CleanedText( "There's a tag after this" ),
- new CleanedTag( '<br />' )
- ];
- $expectedContent = [
- new CleanedText( "There's a tag after this" ),
- new CleanedTag( '<br />' )
- ];
- $segments = Segmenter::segmentSentences( $cleanedContent );
- $this->assertEquals(
- $expectedContent,
- $segments[0]['content']
- );
- }
-
public function testTextOffset() {
$cleanedContent = [ new CleanedText( 'Sentence.' ) ];
$segments = Segmenter::segmentSentences( $cleanedContent );
@@ -130,53 +92,5 @@
$this->assertEquals( 13, $segments[0]['endOffset'] );
$this->assertEquals( 13, $segments[1]['startOffset'] );
$this->assertEquals( 27, $segments[1]['endOffset'] );
- }
-
- public function testTextOffsetWithTags() {
- $cleanedContent = [
- new CleanedText( 'Sentence ' ),
- new CleanedTag( '<i>' ),
- new CleanedText( 'with' ),
- new CleanedTag( '</i>' ),
- new CleanedText( ' a tag.' )
- ];
- $segments = Segmenter::segmentSentences( $cleanedContent );
- $this->assertEquals( 0, $segments[0]['startOffset'] );
- $this->assertEquals( 7, $segments[0]['endOffset'] );
- }
-
- public function testTextOffsetAfterTags() {
- $cleanedContent = [
- new CleanedText( 'Sentence one.' ),
- new CleanedTag( '<br />' ),
- new CleanedText( ' Sentence two.' )
- ];
- $segments = Segmenter::segmentSentences( $cleanedContent );
- $this->assertEquals(
- [
- new CleanedTag( '<br />' ),
- new CleanedText( ' Sentence two.' )
- ],
- $segments[1]['content'] );
- $this->assertEquals( 0, $segments[1]['startOffset'] );
- $this->assertEquals( 14, $segments[1]['endOffset'] );
- }
-
- public function testStartTextOffsetWhenTagInSegment() {
- $cleanedContent = [
- new CleanedText( 'Sentence one. Sentence' ),
- new CleanedTag( '<br />' ),
- new CleanedText( 'two.' )
- ];
- $segments = Segmenter::segmentSentences( $cleanedContent );
- $this->assertEquals(
- [
- new CleanedText( ' Sentence' ),
- new CleanedTag( '<br />' ),
- new CleanedText( 'two.' )
- ],
- $segments[1]['content'] );
- $this->assertEquals( 13, $segments[1]['startOffset'] );
- $this->assertEquals( 4, $segments[1]['endOffset'] );
}
}
diff --git a/tests/qunit/ext.wikispeech.test.js
b/tests/qunit/ext.wikispeech.test.js
index 3a2c881..45d1458 100644
--- a/tests/qunit/ext.wikispeech.test.js
+++ b/tests/qunit/ext.wikispeech.test.js
@@ -538,7 +538,7 @@
assert.expect( 1 );
$( '<content></content>' ).html(
- '<text>Utterance with
</text><cleaned-tag>b</cleaned-tag><text>tag</text><cleaned-tag>/b</cleaned-tag><text>.</text>'
+ '<text>Utterance with
</text><text>tag</text><text>.</text>'
)
.appendTo( $( '#utterance-0' ) );
tokens = [
@@ -579,7 +579,7 @@
assert.expect( 1 );
$( '<content></content>' ).html(
- '<text>Utterance with
</text><cleaned-tag>del</cleaned-tag><text>removed
tag</text><cleaned-tag>/del</cleaned-tag><text>.</text>'
+ '<text>Utterance with </text><text>removed
tag</text><text>.</text>'
)
.appendTo( $( '#utterance-0' ) );
tokens = [
@@ -835,7 +835,7 @@
} );
QUnit.test( 'highlightUtterance()', function ( assert ) {
- assert.expect( 2 );
+ assert.expect( 1 );
$( '#qunit-fixture' ).append(
$( '<div></div>' )
.attr( 'id', 'mw-content-text' )
@@ -845,7 +845,7 @@
$( '<content></content>' )
.append( $( '<text></text>' )
.text( 'An utterance.' )
- .attr( 'path', '0' )
+ .attr( 'path', './text()' )
)
);
$( '#utterance-0' ).attr( 'start-offset', 0 );
@@ -856,10 +856,6 @@
assert.strictEqual(
$( '#mw-content-text' ).prop( 'innerHTML' ),
'<span class="ext-wikispeech-highlight-sentence">An
utterance.</span>'
- );
- assert.strictEqual(
- $( '#mw-content-text' ).prop( 'utterance' ),
- $( 'utterance-0' ).get( 0 )
);
} );
@@ -874,7 +870,7 @@
$( '<content></content>' )
.append( $( '<text></text>' )
.text( ' Utterance two.' )
- .attr( 'path', '0' )
+ .attr( 'path', './text()' )
)
);
$( '#utterance-0' ).attr( 'start-offset', 14 );
@@ -897,23 +893,20 @@
);
$( '#utterance-0' ).append(
$( '<content></content>' )
- .append( $( '<text></text>' )
- .text( 'Utterance with ' )
- .attr( 'path', '0,0' )
+ .append(
+ $( '<text></text>' )
+ .text( 'Utterance with ' )
+ .attr( 'path', './p/text()[1]' )
)
- .append( $( '<cleaned-tag></cleaned-tag>' )
- .text( 'b' )
+ .append(
+ $( '<text></text>' )
+ .text( 'a' )
+ .attr( 'path', './p/b/text()' )
)
- .append( $( '<text></text>' )
- .text( 'a' )
- .attr( 'path', '0,1,0' )
- )
- .append( $( '<cleaned-tag></cleaned-tag>' )
- .text( 'b' )
- )
- .append( $( '<text></text>' )
- .text( ' tag.' )
- .attr( 'path', '0,2' )
+ .append(
+ $( '<text></text>' )
+ .text( ' tag.' )
+ .attr( 'path', './p/text()[2]' )
)
);
$( '#utterance-0' ).attr( 'start-offset', 0 );
@@ -924,6 +917,42 @@
assert.strictEqual(
$( '#mw-content-text' ).prop( 'innerHTML' ),
'<p><span
class="ext-wikispeech-highlight-sentence">Utterance with </span><b><span
class="ext-wikispeech-highlight-sentence">a</span></b><span
class="ext-wikispeech-highlight-sentence"> tag.</span></p>'
+ );
+ } );
+
+ QUnit.test( 'highlightUtterance(): wrap middle text nodes properly',
function ( assert ) {
+ assert.expect( 1 );
+ $( '#qunit-fixture' ).append(
+ $( '<div></div>' )
+ .attr( 'id', 'mw-content-text' )
+ .html( 'First<br />middle<br />last. Next
utterance.' )
+ );
+ $( '#utterance-0' ).append(
+ $( '<content></content>' )
+ .append(
+ $( '<text></text>' )
+ .text( 'First' )
+ .attr( 'path', './text()[1]' )
+ )
+ .append(
+ $( '<text></text>' )
+ .text( 'middle' )
+ .attr( 'path', './text()[2]' )
+ )
+ .append(
+ $( '<text></text>' )
+ .text( 'last.' )
+ .attr( 'path', './text()[3]' )
+ )
+ );
+ $( '#utterance-0' ).attr( 'start-offset', 0 );
+ $( '#utterance-0' ).attr( 'end-offset', 4 );
+
+ wikispeech.highlightUtterance( $( '#utterance-0' ) );
+
+ assert.strictEqual(
+ $( '#mw-content-text' ).prop( 'innerHTML' ),
+ '<span
class="ext-wikispeech-highlight-sentence">First</span><br><span
class="ext-wikispeech-highlight-sentence">middle</span><br><span
class="ext-wikispeech-highlight-sentence">last.</span> Next utterance.'
);
} );
@@ -954,17 +983,6 @@
.attr( 'id', 'mw-content-text' )
.html( 'prefix <span
class="ext-wikispeech-highlight-sentence">An utterance.</span> suffix' )
);
- $( '.ext-wikispeech-highlight-sentence' )
- .prop( 'utterance', $( '#utterance-0' ).get( 0 ) );
- $( '#utterance-0' ).append(
- $( '<content></content>' )
- .append( $( '<text></text>' )
- .text( 'An utterance.' )
- .attr( 'path', '0' )
- )
- );
- $( '#utterance-0' ).attr( 'start-offset', 7 );
- $( '#utterance-0' ).attr( 'end-offset', 19 );
wikispeech.unhighlightUtterances();
@@ -972,11 +990,11 @@
$( '#mw-content-text' ).prop( 'innerHTML' ),
'prefix An utterance. suffix'
);
- assert.strictEqual( $( '#mw-content-text' ).contents().length,
1 );
assert.strictEqual(
$( '.ext-wikispeech-highlight-sentence'
).contents().length,
0
);
+ assert.strictEqual( $( '#mw-content-text' ).contents().length,
1 );
} );
QUnit.test( 'unhighlightUtterance(): multiple highlights', function (
assert ) {
--
To view, visit https://gerrit.wikimedia.org/r/342024
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: Ifec50d6d22a9e3e6adf51d96d315237852aa11ac
Gerrit-PatchSet: 5
Gerrit-Project: mediawiki/extensions/Wikispeech
Gerrit-Branch: master
Gerrit-Owner: Sebastian Berlin (WMSE) <[email protected]>
Gerrit-Reviewer: Lokal Profil <[email protected]>
Gerrit-Reviewer: Sebastian Berlin (WMSE) <[email protected]>
Gerrit-Reviewer: jenkins-bot <>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits