* Move tests to a separate test suite.
* Unit tests already covered these cases without second and third
parameter so no extra tests.
* Update code to clearly make attribs optional.
Bug: T88962
Change-Id: I26bb4b0a907f48064f41236972e115ec1f7edf0c
* Create an HTML element string, with safe escaping.
*
* @param {string} name The tag name.
- * @param {Object} attrs An object with members mapping element names to values
- * @param {Mixed} contents The contents of the element. May be either:
+ * @param {Object} [attrs] An object with members mapping element names to values
+ * @param {string|mw.html.Raw|mw.html.Cdata|null} [contents=null] The contents of the element.
*
- * - string: The string is escaped.
- * - null or undefined: The short closing form is used, e.g. `<br/>`.
- * - this.Raw: The value attribute is included without escaping.
- * - this.Cdata: The value attribute is included, and an exception is
- * thrown if it contains an illegal ETAGO delimiter.
- * See <http://www.w3.org/TR/1999/REC-html401-19991224/appendix/notes.html#h-B.3.2>.
+ * - string: Text to be escaped.
+ * - null: The element is treated as void with short closing form, e.g. `<br/>`.
+ * - this.Raw: The raw value is directly included.
+ * - this.Cdata: The raw value is directly included. An exception is
+ * thrown if it contains any illegal ETAGO delimiter.
+ * See <http://www.w3.org/TR/html401/appendix/notes.html#h-B.3.2>.
* @return {string} HTML
*/
element: function ( name, attrs, contents ) {
var v, attrName, s = '<' + name;
- for ( attrName in attrs ) {
- v = attrs[ attrName ];
- // Convert name=true, to name=name
- if ( v === true ) {
- v = attrName;
- // Skip name=false
- } else if ( v === false ) {
- continue;
+ if ( attrs ) {
+ for ( attrName in attrs ) {
+ v = attrs[ attrName ];
+ // Convert name=true, to name=name
+ if ( v === true ) {
+ v = attrName;
+ // Skip name=false
+ } else if ( v === false ) {
+ continue;
+ }
+ s += ' ' + attrName + '="' + this.escape( String( v ) ) + '"';
}
- s += ' ' + attrName + '="' + this.escape( String( v ) ) + '"';
}
if ( contents === undefined || contents === null ) {
// Self close tag
'tests/qunit/suites/resources/mediawiki/mediawiki.storage.test.js',
'tests/qunit/suites/resources/mediawiki/mediawiki.template.test.js',
'tests/qunit/suites/resources/mediawiki/mediawiki.test.js',
+ 'tests/qunit/suites/resources/mediawiki/mediawiki.html.test.js',
'tests/qunit/suites/resources/mediawiki/mediawiki.Title.test.js',
'tests/qunit/suites/resources/mediawiki/mediawiki.toc.test.js',
'tests/qunit/suites/resources/mediawiki/mediawiki.track.test.js',
--- /dev/null
+( function ( mw ) {
+ QUnit.module( 'mediawiki.html' );
+
+ QUnit.test( 'escape', 2, function ( assert ) {
+ assert.throws(
+ function () {
+ mw.html.escape();
+ },
+ TypeError,
+ 'throw a TypeError if argument is not a string'
+ );
+
+ assert.equal(
+ mw.html.escape( '<mw awesome="awesome" value=\'test\' />' ),
+ '<mw awesome="awesome" value='test' />',
+ 'Escape special characters to html entities'
+ );
+ } );
+
+ QUnit.test( 'element()', 1, function ( assert ) {
+ assert.equal(
+ mw.html.element(),
+ '<undefined/>',
+ 'return valid html even without arguments'
+ );
+ } );
+
+ QUnit.test( 'element( tagName )', 1, function ( assert ) {
+ assert.equal( mw.html.element( 'div' ), '<div/>', 'DIV' );
+ } );
+
+ QUnit.test( 'element( tagName, attrs )', 2, function ( assert ) {
+ assert.equal( mw.html.element( 'div', {} ), '<div/>', 'DIV' );
+
+ assert.equal(
+ mw.html.element(
+ 'div', {
+ id: 'foobar'
+ }
+ ),
+ '<div id="foobar"/>',
+ 'DIV with attribs'
+ );
+ } );
+
+ QUnit.test( 'element( tagName, attrs, content )', 8, function ( assert ) {
+
+ assert.equal( mw.html.element( 'div', {}, '' ), '<div></div>', 'DIV with empty attributes and content' );
+
+ assert.equal( mw.html.element( 'p', {}, 12 ), '<p>12</p>', 'numbers as content cast to strings' );
+
+ assert.equal( mw.html.element( 'p', { title: 12 }, '' ), '<p title="12"></p>', 'number as attribute value' );
+
+ assert.equal(
+ mw.html.element(
+ 'div',
+ {},
+ new mw.html.Raw(
+ mw.html.element( 'img', { src: '<' } )
+ )
+ ),
+ '<div><img src="<"/></div>',
+ 'unescaped content with mw.html.Raw'
+ );
+
+ assert.equal(
+ mw.html.element(
+ 'option',
+ {
+ selected: true
+ },
+ 'Foo'
+ ),
+ '<option selected="selected">Foo</option>',
+ 'boolean true attribute value'
+ );
+
+ assert.equal(
+ mw.html.element(
+ 'option',
+ {
+ value: 'foo',
+ selected: false
+ },
+ 'Foo'
+ ),
+ '<option value="foo">Foo</option>',
+ 'boolean false attribute value'
+ );
+
+ assert.equal(
+ mw.html.element( 'div', null, 'a' ),
+ '<div>a</div>',
+ 'Skip attributes with null' );
+
+ assert.equal(
+ mw.html.element( 'a', {
+ href: 'http://mediawiki.org/w/index.php?title=RL&action=history'
+ }, 'a' ),
+ '<a href="http://mediawiki.org/w/index.php?title=RL&action=history">a</a>',
+ 'Andhor tag with attributes and content'
+ );
+ } );
+
+}( mediaWiki ) );
} ).always( QUnit.start );
} );
- QUnit.test( 'mw.html', 13, function ( assert ) {
- assert.throws( function () {
- mw.html.escape();
- }, TypeError, 'html.escape throws a TypeError if argument given is not a string' );
-
- assert.equal( mw.html.escape( '<mw awesome="awesome" value=\'test\' />' ),
- '<mw awesome="awesome" value='test' />', 'escape() escapes special characters to html entities' );
-
- assert.equal( mw.html.element(),
- '<undefined/>', 'element() always returns a valid html string (even without arguments)' );
-
- assert.equal( mw.html.element( 'div' ), '<div/>', 'element() Plain DIV (simple)' );
-
- assert.equal( mw.html.element( 'div', {}, '' ), '<div></div>', 'element() Basic DIV (simple)' );
-
- assert.equal(
- mw.html.element(
- 'div', {
- id: 'foobar'
- }
- ),
- '<div id="foobar"/>',
- 'html.element DIV (attribs)' );
-
- assert.equal( mw.html.element( 'p', null, 12 ), '<p>12</p>', 'Numbers are valid content and should be casted to a string' );
-
- assert.equal( mw.html.element( 'p', { title: 12 }, '' ), '<p title="12"></p>', 'Numbers are valid attribute values' );
-
- // Example from https://www.mediawiki.org/wiki/ResourceLoader/Default_modules#mediaWiki.html
- assert.equal(
- mw.html.element(
- 'div',
- {},
- new mw.html.Raw(
- mw.html.element( 'img', { src: '<' } )
- )
- ),
- '<div><img src="<"/></div>',
- 'Raw inclusion of another element'
- );
-
- assert.equal(
- mw.html.element(
- 'option', {
- selected: true
- }, 'Foo'
- ),
- '<option selected="selected">Foo</option>',
- 'Attributes may have boolean values. True copies the attribute name to the value.'
- );
-
- assert.equal(
- mw.html.element(
- 'option', {
- value: 'foo',
- selected: false
- }, 'Foo'
- ),
- '<option value="foo">Foo</option>',
- 'Attributes may have boolean values. False keeps the attribute from output.'
- );
-
- assert.equal( mw.html.element( 'div',
- null, 'a' ),
- '<div>a</div>',
- 'html.element DIV (content)' );
-
- assert.equal( mw.html.element( 'a',
- { href: 'http://mediawiki.org/w/index.php?title=RL&action=history' }, 'a' ),
- '<a href="http://mediawiki.org/w/index.php?title=RL&action=history">a</a>',
- 'html.element DIV (attribs + content)' );
-
- } );
-
QUnit.test( 'mw.hook', 13, function ( assert ) {
var hook, add, fire, chars, callback;