From: Derk-Jan Hartman Date: Sat, 31 Oct 2015 15:47:00 +0000 (+0000) Subject: mw.html: Document mw.html.elements optional parameters X-Git-Tag: 1.31.0-rc.0~9151^2 X-Git-Url: https://git.heureux-cyclage.org/?p=lhc%2Fweb%2Fwiklou.git;a=commitdiff_plain;h=69d4d618913752e0795957bfe2d77500866ea808 mw.html: Document mw.html.elements optional parameters * 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 --- diff --git a/resources/src/mediawiki/mediawiki.js b/resources/src/mediawiki/mediawiki.js index 568bfd43bc..3ffe55ffe6 100644 --- a/resources/src/mediawiki/mediawiki.js +++ b/resources/src/mediawiki/mediawiki.js @@ -2377,30 +2377,32 @@ * 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. `
`. - * - 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 . + * - string: Text to be escaped. + * - null: The element is treated as void with short closing form, e.g. `
`. + * - 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 . * @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 diff --git a/tests/qunit/QUnitTestResources.php b/tests/qunit/QUnitTestResources.php index f9ddcf2746..26c4e08185 100644 --- a/tests/qunit/QUnitTestResources.php +++ b/tests/qunit/QUnitTestResources.php @@ -71,6 +71,7 @@ return array( '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', diff --git a/tests/qunit/suites/resources/mediawiki/mediawiki.html.test.js b/tests/qunit/suites/resources/mediawiki/mediawiki.html.test.js new file mode 100644 index 0000000000..b4028ecf5f --- /dev/null +++ b/tests/qunit/suites/resources/mediawiki/mediawiki.html.test.js @@ -0,0 +1,105 @@ +( 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' />', + 'Escape special characters to html entities' + ); + } ); + + QUnit.test( 'element()', 1, function ( assert ) { + assert.equal( + mw.html.element(), + '', + 'return valid html even without arguments' + ); + } ); + + QUnit.test( 'element( tagName )', 1, function ( assert ) { + assert.equal( mw.html.element( 'div' ), '
', 'DIV' ); + } ); + + QUnit.test( 'element( tagName, attrs )', 2, function ( assert ) { + assert.equal( mw.html.element( 'div', {} ), '
', 'DIV' ); + + assert.equal( + mw.html.element( + 'div', { + id: 'foobar' + } + ), + '
', + 'DIV with attribs' + ); + } ); + + QUnit.test( 'element( tagName, attrs, content )', 8, function ( assert ) { + + assert.equal( mw.html.element( 'div', {}, '' ), '
', 'DIV with empty attributes and content' ); + + assert.equal( mw.html.element( 'p', {}, 12 ), '

12

', 'numbers as content cast to strings' ); + + assert.equal( mw.html.element( 'p', { title: 12 }, '' ), '

', 'number as attribute value' ); + + assert.equal( + mw.html.element( + 'div', + {}, + new mw.html.Raw( + mw.html.element( 'img', { src: '<' } ) + ) + ), + '
', + 'unescaped content with mw.html.Raw' + ); + + assert.equal( + mw.html.element( + 'option', + { + selected: true + }, + 'Foo' + ), + '', + 'boolean true attribute value' + ); + + assert.equal( + mw.html.element( + 'option', + { + value: 'foo', + selected: false + }, + 'Foo' + ), + '', + 'boolean false attribute value' + ); + + assert.equal( + mw.html.element( 'div', null, 'a' ), + '
a
', + 'Skip attributes with null' ); + + assert.equal( + mw.html.element( 'a', { + href: 'http://mediawiki.org/w/index.php?title=RL&action=history' + }, 'a' ), + 'a', + 'Andhor tag with attributes and content' + ); + } ); + +}( mediaWiki ) ); diff --git a/tests/qunit/suites/resources/mediawiki/mediawiki.test.js b/tests/qunit/suites/resources/mediawiki/mediawiki.test.js index ac4f16c46c..d205ba7438 100644 --- a/tests/qunit/suites/resources/mediawiki/mediawiki.test.js +++ b/tests/qunit/suites/resources/mediawiki/mediawiki.test.js @@ -964,80 +964,6 @@ } ).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' />', 'escape() escapes special characters to html entities' ); - - assert.equal( mw.html.element(), - '', 'element() always returns a valid html string (even without arguments)' ); - - assert.equal( mw.html.element( 'div' ), '
', 'element() Plain DIV (simple)' ); - - assert.equal( mw.html.element( 'div', {}, '' ), '
', 'element() Basic DIV (simple)' ); - - assert.equal( - mw.html.element( - 'div', { - id: 'foobar' - } - ), - '
', - 'html.element DIV (attribs)' ); - - assert.equal( mw.html.element( 'p', null, 12 ), '

12

', 'Numbers are valid content and should be casted to a string' ); - - assert.equal( mw.html.element( 'p', { title: 12 }, '' ), '

', '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: '<' } ) - ) - ), - '
', - 'Raw inclusion of another element' - ); - - assert.equal( - mw.html.element( - 'option', { - selected: true - }, 'Foo' - ), - '', - 'Attributes may have boolean values. True copies the attribute name to the value.' - ); - - assert.equal( - mw.html.element( - 'option', { - value: 'foo', - selected: false - }, 'Foo' - ), - '', - 'Attributes may have boolean values. False keeps the attribute from output.' - ); - - assert.equal( mw.html.element( 'div', - null, 'a' ), - '
a
', - 'html.element DIV (content)' ); - - assert.equal( mw.html.element( '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;