Jforrester has uploaded a new change for review. ( https://gerrit.wikimedia.org/r/356313 )
Change subject: Update OOjs UI to v0.22.0 ...................................................................... Update OOjs UI to v0.22.0 Release notes: https://phabricator.wikimedia.org/diffusion/GOJU/browse/master/History.md;v0.22.0 Change-Id: I93b66d5339e6766f46dfcc5b22abaeadd74d8da0 --- M composer.json M composer.lock M composer/autoload_classmap.php M composer/autoload_static.php M composer/installed.json M oojs/oojs-ui/.mailmap M oojs/oojs-ui/AUTHORS.txt M oojs/oojs-ui/History.md M oojs/oojs-ui/README.md M oojs/oojs-ui/bin/generate-JSPHP-for-karma.php M oojs/oojs-ui/bin/testsuitegenerator.rb M oojs/oojs-ui/demos/classes/CapsuleNumberPopupMultiselectWidget.js M oojs/oojs-ui/demos/classes/NumberLookupTextInputWidget.js M oojs/oojs-ui/demos/demo.js M oojs/oojs-ui/demos/demos.php M oojs/oojs-ui/demos/index.html M oojs/oojs-ui/demos/pages/widgets.js M oojs/oojs-ui/demos/pages/widgets.php M oojs/oojs-ui/demos/styles/demo.css M oojs/oojs-ui/i18n/id.json M oojs/oojs-ui/package.json M oojs/oojs-ui/php/themes/MediaWikiTheme.php A oojs/oojs-ui/php/themes/WikimediaUITheme.php M oojs/oojs-ui/php/widgets/CheckboxInputWidget.php A oojs/oojs-ui/php/widgets/HiddenInputWidget.php M oojs/oojs-ui/php/widgets/InputWidget.php M oojs/oojs-ui/php/widgets/RadioInputWidget.php M oojs/oojs-ui/php/widgets/TextInputWidget.php 28 files changed, 1,679 insertions(+), 1,045 deletions(-) git pull ssh://gerrit.wikimedia.org:29418/mediawiki/vendor refs/changes/13/356313/1 diff --git a/composer.json b/composer.json index 069e0a1..bd33908 100644 --- a/composer.json +++ b/composer.json @@ -45,7 +45,7 @@ "monolog/monolog": "1.22.1", "mustangostang/spyc": "0.6.2", "nmred/kafka-php": "0.1.5", - "oojs/oojs-ui": "0.21.4", + "oojs/oojs-ui": "0.22.0", "oyejorge/less.php": "1.7.0.14", "pear/console_getopt": "1.4.1", "pear/mail": "1.3.0", diff --git a/composer.lock b/composer.lock index 8baa3b0..09a7ae4 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "content-hash": "c718138a0d49641945b13ec3d33e43c4", + "content-hash": "b11c2cf5cde1b9f593e047ef0f5ceba7", "packages": [ { "name": "composer/semver", @@ -516,16 +516,16 @@ }, { "name": "oojs/oojs-ui", - "version": "v0.21.4", + "version": "v0.22.0", "source": { "type": "git", "url": "https://github.com/wikimedia/oojs-ui.git", - "reference": "ed5dd92664b765a160e68e46ec0337e75451b0ad" + "reference": "7266f93803bafb52df22925fda743cbe35a84b98" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/wikimedia/oojs-ui/zipball/ed5dd92664b765a160e68e46ec0337e75451b0ad", - "reference": "ed5dd92664b765a160e68e46ec0337e75451b0ad", + "url": "https://api.github.com/repos/wikimedia/oojs-ui/zipball/7266f93803bafb52df22925fda743cbe35a84b98", + "reference": "7266f93803bafb52df22925fda743cbe35a84b98", "shasum": "" }, "require": { @@ -591,7 +591,7 @@ ], "description": "Provides library of common widgets, layouts, and windows.", "homepage": "https://www.mediawiki.org/wiki/OOjs_UI", - "time": "2017-05-16T22:09:22+00:00" + "time": "2017-05-30T22:02:38+00:00" }, { "name": "oyejorge/less.php", diff --git a/composer/autoload_classmap.php b/composer/autoload_classmap.php index eebf93e..f67b0ac 100644 --- a/composer/autoload_classmap.php +++ b/composer/autoload_classmap.php @@ -534,6 +534,7 @@ 'OOUI\\FlaggedElement' => $vendorDir . '/oojs/oojs-ui/php/mixins/FlaggedElement.php', 'OOUI\\FormLayout' => $vendorDir . '/oojs/oojs-ui/php/layouts/FormLayout.php', 'OOUI\\GroupElement' => $vendorDir . '/oojs/oojs-ui/php/mixins/GroupElement.php', + 'OOUI\\HiddenInputWidget' => $vendorDir . '/oojs/oojs-ui/php/widgets/HiddenInputWidget.php', 'OOUI\\HorizontalLayout' => $vendorDir . '/oojs/oojs-ui/php/layouts/HorizontalLayout.php', 'OOUI\\HtmlSnippet' => $vendorDir . '/oojs/oojs-ui/php/HtmlSnippet.php', 'OOUI\\IconElement' => $vendorDir . '/oojs/oojs-ui/php/mixins/IconElement.php', @@ -555,6 +556,7 @@ 'OOUI\\Theme' => $vendorDir . '/oojs/oojs-ui/php/Theme.php', 'OOUI\\TitledElement' => $vendorDir . '/oojs/oojs-ui/php/mixins/TitledElement.php', 'OOUI\\Widget' => $vendorDir . '/oojs/oojs-ui/php/Widget.php', + 'OOUI\\WikimediaUITheme' => $vendorDir . '/oojs/oojs-ui/php/themes/WikimediaUITheme.php', 'OS_Guess' => $vendorDir . '/pear/pear-core-minimal/src/OS/Guess.php', 'PEAR' => $vendorDir . '/pear/pear-core-minimal/src/PEAR.php', 'PEAR_Error' => $vendorDir . '/pear/pear-core-minimal/src/PEAR.php', diff --git a/composer/autoload_static.php b/composer/autoload_static.php index 6900e49..5e293f1 100644 --- a/composer/autoload_static.php +++ b/composer/autoload_static.php @@ -720,6 +720,7 @@ 'OOUI\\FlaggedElement' => __DIR__ . '/..' . '/oojs/oojs-ui/php/mixins/FlaggedElement.php', 'OOUI\\FormLayout' => __DIR__ . '/..' . '/oojs/oojs-ui/php/layouts/FormLayout.php', 'OOUI\\GroupElement' => __DIR__ . '/..' . '/oojs/oojs-ui/php/mixins/GroupElement.php', + 'OOUI\\HiddenInputWidget' => __DIR__ . '/..' . '/oojs/oojs-ui/php/widgets/HiddenInputWidget.php', 'OOUI\\HorizontalLayout' => __DIR__ . '/..' . '/oojs/oojs-ui/php/layouts/HorizontalLayout.php', 'OOUI\\HtmlSnippet' => __DIR__ . '/..' . '/oojs/oojs-ui/php/HtmlSnippet.php', 'OOUI\\IconElement' => __DIR__ . '/..' . '/oojs/oojs-ui/php/mixins/IconElement.php', @@ -741,6 +742,7 @@ 'OOUI\\Theme' => __DIR__ . '/..' . '/oojs/oojs-ui/php/Theme.php', 'OOUI\\TitledElement' => __DIR__ . '/..' . '/oojs/oojs-ui/php/mixins/TitledElement.php', 'OOUI\\Widget' => __DIR__ . '/..' . '/oojs/oojs-ui/php/Widget.php', + 'OOUI\\WikimediaUITheme' => __DIR__ . '/..' . '/oojs/oojs-ui/php/themes/WikimediaUITheme.php', 'OS_Guess' => __DIR__ . '/..' . '/pear/pear-core-minimal/src/OS/Guess.php', 'PEAR' => __DIR__ . '/..' . '/pear/pear-core-minimal/src/PEAR.php', 'PEAR_Error' => __DIR__ . '/..' . '/pear/pear-core-minimal/src/PEAR.php', diff --git a/composer/installed.json b/composer/installed.json index ccb05f4..c221a6c 100644 --- a/composer/installed.json +++ b/composer/installed.json @@ -2163,18 +2163,70 @@ "homepage": "https://www.mediawiki.org/wiki/Testing-access-wrapper" }, { - "name": "oojs/oojs-ui", - "version": "v0.21.4", - "version_normalized": "0.21.4.0", + "name": "mustangostang/spyc", + "version": "0.6.2", + "version_normalized": "0.6.2.0", "source": { "type": "git", - "url": "https://github.com/wikimedia/oojs-ui.git", - "reference": "ed5dd92664b765a160e68e46ec0337e75451b0ad" + "url": "https://github.com/mustangostang/spyc.git", + "reference": "23c35ae854d835f2d7bcc3e3ad743d7e57a8c14d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/wikimedia/oojs-ui/zipball/ed5dd92664b765a160e68e46ec0337e75451b0ad", - "reference": "ed5dd92664b765a160e68e46ec0337e75451b0ad", + "url": "https://api.github.com/repos/mustangostang/spyc/zipball/23c35ae854d835f2d7bcc3e3ad743d7e57a8c14d", + "reference": "23c35ae854d835f2d7bcc3e3ad743d7e57a8c14d", + "shasum": "" + }, + "require": { + "php": ">=5.3.1" + }, + "require-dev": { + "phpunit/phpunit": "4.3.*@dev" + }, + "time": "2017-02-24T16:06:33+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "0.5.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "files": [ + "Spyc.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "mustangostang", + "email": "[email protected]" + } + ], + "description": "A simple YAML loader/dumper class for PHP", + "homepage": "https://github.com/mustangostang/spyc/", + "keywords": [ + "spyc", + "yaml", + "yml" + ] + }, + { + "name": "oojs/oojs-ui", + "version": "v0.22.0", + "version_normalized": "0.22.0.0", + "source": { + "type": "git", + "url": "https://github.com/wikimedia/oojs-ui.git", + "reference": "7266f93803bafb52df22925fda743cbe35a84b98" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/wikimedia/oojs-ui/zipball/7266f93803bafb52df22925fda743cbe35a84b98", + "reference": "7266f93803bafb52df22925fda743cbe35a84b98", "shasum": "" }, "require": { @@ -2186,7 +2238,7 @@ "mediawiki/mediawiki-codesniffer": "0.6.0", "phpunit/phpunit": "4.8.21" }, - "time": "2017-05-16T22:09:22+00:00", + "time": "2017-05-30T22:02:38+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -2242,57 +2294,5 @@ ], "description": "Provides library of common widgets, layouts, and windows.", "homepage": "https://www.mediawiki.org/wiki/OOjs_UI" - }, - { - "name": "mustangostang/spyc", - "version": "0.6.2", - "version_normalized": "0.6.2.0", - "source": { - "type": "git", - "url": "https://github.com/mustangostang/spyc.git", - "reference": "23c35ae854d835f2d7bcc3e3ad743d7e57a8c14d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/mustangostang/spyc/zipball/23c35ae854d835f2d7bcc3e3ad743d7e57a8c14d", - "reference": "23c35ae854d835f2d7bcc3e3ad743d7e57a8c14d", - "shasum": "" - }, - "require": { - "php": ">=5.3.1" - }, - "require-dev": { - "phpunit/phpunit": "4.3.*@dev" - }, - "time": "2017-02-24T16:06:33+00:00", - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "0.5.x-dev" - } - }, - "installation-source": "dist", - "autoload": { - "files": [ - "Spyc.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "mustangostang", - "email": "[email protected]" - } - ], - "description": "A simple YAML loader/dumper class for PHP", - "homepage": "https://github.com/mustangostang/spyc/", - "keywords": [ - "spyc", - "yaml", - "yml" - ] } ] diff --git a/oojs/oojs-ui/.mailmap b/oojs/oojs-ui/.mailmap index 3ec803b..b95bbc8 100644 --- a/oojs/oojs-ui/.mailmap +++ b/oojs/oojs-ui/.mailmap @@ -1,8 +1,8 @@ Alex Monk <[email protected]> Alex Monk <[email protected]> <[email protected]> Bartosz Dziewoński <[email protected]> -Bartosz Dziewoński <[email protected]> <[email protected]> Bartosz Dziewoński <[email protected]> <[email protected]> +Bartosz Dziewoński <[email protected]> <[email protected]> Christian Williams <[email protected]> Christian Williams <[email protected]> <christian@localhost> Christian Williams <[email protected]> <[email protected]> @@ -16,16 +16,27 @@ Inez Korczyński <[email protected]> Inez Korczyński <[email protected]> <[email protected]> James D. Forrester <[email protected]> +Jon Robson <[email protected]> +Juliusz Gonera <[email protected]> +Juliusz Gonera <[email protected]> Kirsten Menger-Anderson <[email protected]> +Kunal Mehta <[email protected]> +Kunal Mehta <[email protected]> <[email protected]> Marielle Volz <[email protected]> +May Tee-Galloway <[email protected]> +May Tee-Galloway <[email protected]> <[email protected]> Moriel Schottlender <[email protected]> Moriel Schottlender <[email protected]> <[email protected]> +Prateek Saxena <[email protected]> +Prateek Saxena <[email protected]> <[email protected]> Roan Kattouw <[email protected]> Roan Kattouw <[email protected]> <[email protected]> Roan Kattouw <[email protected]> <[email protected]> Rob Moen <[email protected]> Rob Moen <[email protected]> <[email protected]> Rob Moen <[email protected]> <[email protected]> +Sam Reed <[email protected]> +Sam Reed <[email protected]> <[email protected]> Sucheta Ghoshal <[email protected]> Thalia Chan <[email protected]> Thalia Chan <[email protected]> <[email protected]> @@ -34,5 +45,7 @@ Trevor Parscal <[email protected]> Trevor Parscal <[email protected]> <[email protected]> Trevor Parscal <[email protected]> <[email protected]> +Volker E. <[email protected]> +Volker E. <[email protected]> <[email protected]> Željko Filipin <[email protected]> Željko Filipin <[email protected]> <[email protected]> diff --git a/oojs/oojs-ui/AUTHORS.txt b/oojs/oojs-ui/AUTHORS.txt index a17f3a4..52b4888 100644 --- a/oojs/oojs-ui/AUTHORS.txt +++ b/oojs/oojs-ui/AUTHORS.txt @@ -5,35 +5,54 @@ James D. Forrester <[email protected]> Kirsten Menger-Anderson <[email protected]> Kunal Mehta <[email protected]> +Moriel Schottlender <[email protected]> Prateek Saxena <[email protected]> Roan Kattouw <[email protected]> Rob Moen <[email protected]> Timo Tijhof <[email protected]> Trevor Parscal <[email protected]> +Volker E. <[email protected]> Patch Contributors (minor contributors, alphabetically) +Alangi Derick <[email protected]> Alex Monk <[email protected]> Amir E. Aharoni <[email protected]> +Amir Sarabadani <[email protected]> +Andrew Garrett <[email protected]> +Andrew Green <[email protected]> Antoine Musso <[email protected]> Brad Jorsch <[email protected]> +Brion Vibber <[email protected]> C. Scott Ananian <[email protected]> +Chad Horohoe <[email protected]> +codynguyen1116 <[email protected]> David Lynch <[email protected]> Derk-Jan Hartman <[email protected]> eranroz <[email protected]> Erick Guan <[email protected]> Erik Moeller <[email protected]> Florian <[email protected]> +Geoffrey Mon <[email protected]> Gilles Dubuc <[email protected]> -Inez Korczyński <[email protected]> +Huji Lee <[email protected]> +Inez Korczyński <[email protected]> +IvanFon <[email protected]> +Jon Robson <[email protected]> Juliusz Gonera <[email protected]> +Kartik Mistry <[email protected]> Kyle Florence <[email protected]> +Leszek Manicki <[email protected]> +Marc A. Pelletier <[email protected]> +Mark Holmquist <[email protected]> Matthew Flaschen <[email protected]> May Tee-Galloway <[email protected]> -Moriel Schottlender <[email protected]> Mr. Stradivarius <[email protected]> Niklas Laxström <[email protected]> Nirzar Pangarkar <[email protected]> +Ori Livneh <[email protected]> +Paladox <[email protected]> +Pau Giner <[email protected]> Ricordisamoa <[email protected]> rillke <[email protected]> Ryan Kaldari <[email protected]> @@ -41,6 +60,6 @@ Stephane Bisson <[email protected]> Sucheta Ghoshal <[email protected]> Thalia Chan <[email protected]> -Volker Eckl <[email protected]> +Victor Barbu <[email protected]> Wei-Ko Kao <[email protected]> Željko Filipin <[email protected]> diff --git a/oojs/oojs-ui/History.md b/oojs/oojs-ui/History.md index 43652e2..8ea366a 100644 --- a/oojs/oojs-ui/History.md +++ b/oojs/oojs-ui/History.md @@ -1,4 +1,61 @@ # OOjs UI Release History +## v0.22.0 / 2017-05-30 +### Breaking changes +* [BREAKING CHANGE] TextInputWidget: Remove search related methods (Prateek Saxena) +* [BREAKING CHANGE] icons: Drop the core icon pack (James D. Forrester) +* [BREAKING CHANGE] icons: Remove unused 'bookmark' icon (Volker E.) + +### Deprecations +* [DEPRECATING CHANGE] Rename the 'MediaWiki' theme to 'WikimediaUI' (James D. Forrester) +* [DEPRECATING CHANGE] WindowManager: Deprecate using `openWindow`/`closeWindow` returns as promises (Bartosz Dziewoński) + +### Features +* Add HiddenInputWidget to generate hidden input (Victor Barbu) +* InputWidget: Introduce `#setInputId` and `inputId` config option (Bartosz Dziewoński) +* MenuTagMultiselectWidget: Clear text field after adding an item from it (Bartosz Dziewoński) +* MenuTagMultiselectWidget: Handle the 'selected' config option (Bartosz Dziewoński) +* NumberInputWidget: Use icons instead of labels (Volker E.) +* PopupButtonWidget: Handle empty configuration (Bartosz Dziewoński) +* PopupWidget: Position close button in head absolutely (David Lynch) +* PopupWidget: Sensibly position anchor-less popups (Roan Kattouw) +* WindowManager: Add `WindowInstance` - a Promise-based lifecycle object (Timo Tijhof) +* WindowManager: Handle errors better in `#closeWindow` (Bartosz Dziewoński) + +* Allow *even more* widgets to be focussed programatically (Bartosz Dziewoński) +* Only cancel mouse down event if tool in toolgroup clicked on (Ed Sanders) +* Re-introduce `.simulateLabelClick()` as a separate method from .focus() (Bartosz Dziewoński) + +### Styles +* themes: Field*Layout help position perfectly aligned (Volker E.) +* themes: Improve frameless button in size and behaviour (Volker E.) +* themes: Increase FieldsetLayout header's `font-size` (Volker E.) +* Apex theme: Ensure vertical centering of ButtonElement's icon (Volker E.) +* Apex theme: Make OptionWidget icon override more specific (Moriel Schottlender) +* Apex theme: Start Apex's 'user' icon pack, with just 'userAvatar' for now (Ed Sanders) +* WikimediaUI theme: Align `@background-color-destructive` to WikimediaUI Base (Volker E.) +* WikimediaUI theme: Align ButtonInputWidget's `line-height` to ButtonWidget (Volker E.) +* WikimediaUI theme: Align inline label's position (Volker E.) +* WikimediaUI theme: Ensure icon aligns in dropdown menu (Volker E.) +* WikimediaUI theme: Remove incorrect comments (Volker E.) + +### Code +* MenuTagMultiselectWidget: Add test for 'selected' config option (Bartosz Dziewoński) +* windows: Add tests for OO.ui.alert/confirm/prompt (Timo Tijhof) +* AUTHORS: Update for the past two years' work (James D. Forrester) +* build: Add the README/AUTHORS/LICENCE files to dist (James D. Forrester) +* demos: Add TextInputWidget examples with inline labels but no indicators (Ed Sanders) +* demos: Add viewport meta tag to PHP demo too (Volker E.) +* demos: Avoid inline CSS for the overlay (Bartosz Dziewoński) +* demos: Fix code generation for more complicated cases (Bartosz Dziewoński) +* demos: Fix up a couple of minor things in demo widgets (Bartosz Dziewoński) +* demos: Fix `z-index` with fixed demo header (Volker E.) +* demos: Increase and strengthen responsive support (Volker E.) +* demos: Indicate widgets clearer by sections (Volker E.) +* demos: Make disabled progress bar in demo determinate (Ed Sanders) +* demos: Show code that can be used to create the widget (Prateek Saxena) +* testsuitegenerator: Handle classes with no constructor (Bartosz Dziewoński) + + ## v0.21.4 / 2017-05-16 ### Features * Allow more widgets to be focussed programatically (Bartosz Dziewoński) diff --git a/oojs/oojs-ui/README.md b/oojs/oojs-ui/README.md index 0a2f0e2..6ee88c4 100644 --- a/oojs/oojs-ui/README.md +++ b/oojs/oojs-ui/README.md @@ -35,9 +35,9 @@ While the distribution directory is chock-full of files, you will normally only need to load three: -* `oojs-ui.js`, containing the full library -* One of `oojs-ui-mediawiki.css` or `oojs-ui-apex.css`, containing theme-specific styles -* One of `oojs-ui-mediawiki.js` or `oojs-ui-apex.js`, containing theme-specific code +* `oojs-ui.js`, containing the full library; +* One of `oojs-ui-wikimediaui.css` or `oojs-ui-apex.css`, containing theme-specific styles; and +* One of `oojs-ui-wikimediaui.js` or `oojs-ui-apex.js`, containing theme-specific code You can load additional icon packs from files named `oojs-ui-mediawiki-icons-*.css` or `oojs-ui-apex-icons-*.css`. diff --git a/oojs/oojs-ui/bin/generate-JSPHP-for-karma.php b/oojs/oojs-ui/bin/generate-JSPHP-for-karma.php index faadd70..c58e1d2 100644 --- a/oojs/oojs-ui/bin/generate-JSPHP-for-karma.php +++ b/oojs/oojs-ui/bin/generate-JSPHP-for-karma.php @@ -24,7 +24,7 @@ } } // Keep synchronized with tests/index.php -$themes = [ 'ApexTheme', 'MediaWikiTheme' ]; +$themes = [ 'ApexTheme', 'WikimediaUITheme' ]; foreach ( $themes as $theme ) { OOUI\Theme::setSingleton( new_OOUI( $theme ) ); foreach ( $testSuite as $className => $tests ) { diff --git a/oojs/oojs-ui/bin/testsuitegenerator.rb b/oojs/oojs-ui/bin/testsuitegenerator.rb index f0da93e..bada71b 100644 --- a/oojs/oojs-ui/bin/testsuitegenerator.rb +++ b/oojs/oojs-ui/bin/testsuitegenerator.rb @@ -21,6 +21,7 @@ testable_classes = classes .reject{|c| c[:abstract] } # can't test abstract classes .reject{|c| !c[:parent] || c[:trait] || c[:parent] == 'Theme' } # can't test abstract + .reject{|c| c[:name] == 'MediaWikiTheme' } # can't test abstract .reject{|c| %w[Element Widget Layout Theme].include? c[:name] } # no toplevel make_class_instance_placeholder = lambda do |klass, config| @@ -105,7 +106,8 @@ vals = expandos[t] elsif testable_classes.find{|c| c[:name] == t } # OOUI object. Test suite will instantiate one and run the test with it. - params = find_class.call(t)[:methods][0][:params] || [] + constructor = find_class.call(t)[:methods].find{|m| m[:name] == '#constructor' } + params = constructor ? (constructor[:params] || []) : [] config = params.map{|config_option| types = config_option[:type].split '|' values = expand_types_to_values.call(types) @@ -145,9 +147,10 @@ } config_sources = find_config_sources.call(class_name) - .map{|c| find_class.call(c)[:methods][0] } - config = config_sources.map{|c| c[:config] }.compact.inject(:+) - required_config = klass[:methods][0][:params] || [] + .map{|c| find_class.call(c)[:methods].find{|m| m[:name] == '#constructor' } } + config = config_sources.compact.map{|c| c[:config] }.compact.inject([], :+) + constructor = klass[:methods].find{|m| m[:name] == '#constructor' } + required_config = constructor ? (constructor[:params] || []) : [] # generate every possible configuration of configuration option sets maxlength = [config.length, 2].min diff --git a/oojs/oojs-ui/demos/classes/CapsuleNumberPopupMultiselectWidget.js b/oojs/oojs-ui/demos/classes/CapsuleNumberPopupMultiselectWidget.js index ca8a533..5cf3826 100644 --- a/oojs/oojs-ui/demos/classes/CapsuleNumberPopupMultiselectWidget.js +++ b/oojs/oojs-ui/demos/classes/CapsuleNumberPopupMultiselectWidget.js @@ -7,11 +7,14 @@ // Parent constructor Demo.CapsuleNumberPopupMultiselectWidget.parent.call( this, $.extend( {}, config, { allowArbitrary: true, - popup: { $content: this.capsulePopupWidget.$element } + popup: {} } ) ); // Events this.capsulePopupWidget.connect( this, { enter: 'onPopupEnter' } ); + + // Initialization + this.popup.$body.append( this.capsulePopupWidget.$element ); }; OO.inheritClass( Demo.CapsuleNumberPopupMultiselectWidget, OO.ui.CapsuleMultiselectWidget ); diff --git a/oojs/oojs-ui/demos/classes/NumberLookupTextInputWidget.js b/oojs/oojs-ui/demos/classes/NumberLookupTextInputWidget.js index 97d0753..7ad5d16 100644 --- a/oojs/oojs-ui/demos/classes/NumberLookupTextInputWidget.js +++ b/oojs/oojs-ui/demos/classes/NumberLookupTextInputWidget.js @@ -10,7 +10,7 @@ */ Demo.NumberLookupTextInputWidget = function DemoNumberLookupTextInputWidget( config ) { // Parent constructor - OO.ui.TextInputWidget.call( this, { validate: 'integer' } ); + OO.ui.TextInputWidget.call( this, $.extend( { validate: 'integer' }, config ) ); // Mixin constructors OO.ui.mixin.LookupElement.call( this, config ); }; diff --git a/oojs/oojs-ui/demos/demo.js b/oojs/oojs-ui/demos/demo.js index c1d682c..3c8dc00 100644 --- a/oojs/oojs-ui/demos/demo.js +++ b/oojs/oojs-ui/demos/demo.js @@ -1,4 +1,5 @@ /* eslint-disable no-console */ +/* globals Prism */ /** * @class * @extends {OO.ui.Element} @@ -63,6 +64,7 @@ this.documentationLink = new OO.ui.ButtonWidget( { label: 'Docs', + classes: [ 'demo-button-docs' ], icon: 'journal', href: '../js/', flags: [ 'progressive' ] @@ -130,7 +132,7 @@ * @property {Object.<string,string>} */ Demo.static.themes = { - mediawiki: 'MediaWiki', // Do not change this line or you'll break `grunt add-theme` + wikimediaui: 'WikimediaUI', // Do not change this line or you'll break `grunt add-theme` apex: 'Apex' }; @@ -141,7 +143,7 @@ * @property {Object.<string,string[]> */ Demo.static.additionalThemeImagesSuffixes = { - mediawiki: [ + wikimediaui: [ '-icons-movement', '-icons-content', '-icons-alerts', @@ -169,6 +171,7 @@ '-icons-editing-list', '-icons-editing-advanced', '-icons-media', + '-icons-user', '-icons-layout' ] }; @@ -211,7 +214,7 @@ * @static * @property {string} */ -Demo.static.defaultTheme = 'mediawiki'; +Demo.static.defaultTheme = 'wikimediaui'; /** * Default page. @@ -435,8 +438,8 @@ * @param {string} widget Variable name for layout's field widget * @return {jQuery} Console interface element */ -Demo.prototype.buildConsole = function ( item, layout, widget ) { - var $toggle, $log, $label, $input, $submit, $console, $form, +Demo.prototype.buildConsole = function ( item, layout, widget, showLayoutCode ) { + var $toggle, $log, $label, $input, $submit, $console, $form, $pre, $code, console = window.console; function exec( str ) { @@ -498,10 +501,107 @@ $log.prop( 'scrollTop', $log.prop( 'scrollHeight' ) ); } + function getCode( item ) { + var config, isDemoWidget, constructorName, defaultConfig, url, params, out, + replaceKeyword = 'replace-', + replaceLater = []; + + // If no item was passed we shouldn't show a code block + if ( item === undefined ) { + return false; + } + + isDemoWidget = item.constructor.name.indexOf( 'Demo' ) === 0; + config = item.initialConfig; + constructorName = ( isDemoWidget ? 'Demo.' : 'OO.ui.' ) + item.constructor.name.slice( 4 ); + + // Prevent the default config from being part of the code + if ( item instanceof OO.ui.ActionFieldLayout ) { + defaultConfig = ( new item.constructor( new OO.ui.TextInputWidget(), new OO.ui.ButtonWidget() ) ).initialConfig; + } else if ( item instanceof OO.ui.FieldLayout ) { + defaultConfig = ( new item.constructor( new OO.ui.ButtonWidget() ) ).initialConfig; + } else { + defaultConfig = ( new item.constructor() ).initialConfig; + } + Object.keys( defaultConfig ).forEach( function ( key ) { + if ( config[ key ] === defaultConfig[ key ] ) { + delete config[ key ]; + } else if ( + typeof config[ key ] === 'object' && typeof defaultConfig[ key ] === 'object' && + OO.compare( config[ key ], defaultConfig[ key ] ) + ) { + delete config[ key ]; + } + } ); + + config = JSON.stringify( config, function ( k, v ) { + if ( v instanceof OO.ui.Element || v instanceof OO.ui.HtmlSnippet || v instanceof jQuery || v instanceof Function ) { + replaceLater.push( v ); + return replaceKeyword + ( replaceLater.length - 1 ).toString(); + } + return v; + }, '\t' ); + + // We replace later, because running getCode in place will treat the new code + // as a string and won't do proper indentation either + replaceLater.forEach( function ( obj, i ) { + config = config.replace( + // Match any number of tabs (for indentation) and optional object key, followed by our placeholder + new RegExp( '(\t*)("[^"]+?": |)"' + replaceKeyword + i + '"' ), + function ( all, indent, objectKey ) { + var code; + if ( obj instanceof Function ) { + // Get function's source code, with extraneous indentation removed + code = obj.toString().replace( /^\t\t\t\t\t\t/gm, '' ); + } else if ( obj instanceof jQuery ) { + if ( $.contains( item.$element[ 0 ], obj[ 0 ] ) ) { + // If this element appears inside the generated widget, + // assume this was something like `$label: $( '<p>Text</p>' )` + code = '$( \"' + obj.prop( 'outerHTML' ).replace( /'/g, '\\\'' ) + '\" )'; + } else { + // Otherwise assume this was something like `$overlay: $( '#overlay' )` + code = '$( \"#' + obj.attr( 'id' ) + '\" )'; + } + } else if ( obj instanceof OO.ui.HtmlSnippet ) { + code = 'new OO.ui.HtmlSnippet( "' + obj.toString() + '" )'; + } else { + code = getCode( obj ); + } + // Re-add the indent at the beginning, and after every newline + return indent + objectKey + code.replace( /\n/g, '\n' + indent ); + } + ); + } ); + + // The generated code needs to include different arguments, based on the object type + if ( item instanceof OO.ui.ActionFieldLayout ) { + params = getCode( item.fieldWidget ) + ', ' + getCode( item.buttonWidget ); + } else if ( item instanceof OO.ui.FieldLayout ) { + params = getCode( item.fieldWidget ); + } else { + params = ''; + } + if ( config !== '{}' ) { + params += ( params ? ', ' : '' ) + config; + } + out = 'new ' + constructorName + '(' + ( params ? ' ' : '' ) + params + ( params ? ' ' : '' ) + ')'; + + // The code generated for Demo widgets cannot be copied and used + if ( item.constructor.name.indexOf( 'Demo' ) === 0 ) { + url = + 'https://phabricator.wikimedia.org/diffusion/GOJU/browse/master/demos/classes/' + + item.constructor.name.slice( 4 ) + '.js'; + out = '// See source code:\n// ' + url + '\n' + out; + } + + return out; + } + $toggle = $( '<span>' ) .addClass( 'demo-console-toggle' ) .attr( 'title', 'Toggle console' ) .on( 'click', function ( e ) { + var code; e.preventDefault(); $console.toggleClass( 'demo-console-collapsed demo-console-expanded' ); if ( $input.is( ':visible' ) ) { @@ -511,6 +611,19 @@ window[ widget ] = item.fieldWidget; console.log( '[demo]', 'Globals ' + layout + ', ' + widget + ' have been set' ); console.log( '[demo]', item ); + + if ( showLayoutCode === true ) { + code = getCode( item ); + } else { + code = getCode( item.fieldWidget ); + } + + if ( code ) { + $code.text( code ); + Prism.highlightElement( $code[ 0 ] ); + } else { + $code.remove(); + } } } } ); @@ -535,6 +648,12 @@ submit(); } ); + $code = $( '<code>' ).addClass( 'language-javascript' ); + + $pre = $( '<pre>' ) + .addClass( 'demo-sample-code' ) + .append( $code ); + $console = $( '<div>' ) .addClass( 'demo-console demo-console-collapsed' ) .append( @@ -545,7 +664,8 @@ $input ), $submit - ) + ), + $pre ); return $console; diff --git a/oojs/oojs-ui/demos/demos.php b/oojs/oojs-ui/demos/demos.php index bd22c06..ac95d30 100644 --- a/oojs/oojs-ui/demos/demos.php +++ b/oojs/oojs-ui/demos/demos.php @@ -10,11 +10,11 @@ require_once 'classes/ButtonStyleShowcaseWidget.php'; $themes = [ - 'mediawiki' => 'MediaWiki', // Do not change this line or you'll break `grunt add-theme` + 'wikimediaui' => 'WikimediaUI', // Do not change this line or you'll break `grunt add-theme` 'apex' => 'Apex', ]; $theme = ( isset( $_GET['theme'] ) && isset( $themes[ $_GET['theme'] ] ) ) - ? $_GET['theme'] : 'mediawiki'; + ? $_GET['theme'] : 'wikimediaui'; $themeClass = 'OOUI\\' . $themes[ $theme ] . 'Theme'; OOUI\Theme::setSingleton( new $themeClass() ); @@ -44,6 +44,7 @@ <head> <meta charset="UTF-8"> <title>OOjs UI Widget Demo</title> + <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="dist/<?php echo $styleFileName; ?>"> <link rel="stylesheet" href="dist/<?php echo $styleFileNameImages; ?>"> <link rel="stylesheet" href="dist/<?php echo $styleFileNameExtraIcons; ?>"> diff --git a/oojs/oojs-ui/demos/index.html b/oojs/oojs-ui/demos/index.html index 89c721f..cabe444 100644 --- a/oojs/oojs-ui/demos/index.html +++ b/oojs/oojs-ui/demos/index.html @@ -7,12 +7,15 @@ <link rel="stylesheet" href="classes/ButtonStyleShowcaseWidget.css"> <link rel="stylesheet" href="classes/FloatableTest.css"> <link rel="stylesheet" href="classes/PositionSelectWidget.css"> + <link rel="stylesheet" href="node_modules/prismjs/themes/prism.css"> </head> <body> <script src="node_modules/jquery/dist/jquery.js"></script> <script src="node_modules/oojs/dist/oojs.jquery.js"></script> + <script src="node_modules/prismjs/prism.js"></script> + <script src="node_modules/prismjs/plugins/autolinker/prism-autolinker.js"></script> <script src="dist/oojs-ui.js"></script> - <script src="dist/oojs-ui-mediawiki.js"></script> <!-- Do not change this line or you'll break `grunt add-theme` --> + <script src="dist/oojs-ui-wikimediaui.js"></script> <!-- Do not change this line or you'll break `grunt add-theme` --> <script src="dist/oojs-ui-apex.js"></script> <script src="demo.js"></script> <script src="classes/ButtonStyleShowcaseWidget.js"></script> diff --git a/oojs/oojs-ui/demos/pages/widgets.js b/oojs/oojs-ui/demos/pages/widgets.js index 0c951a5..6f30c6b 100644 --- a/oojs/oojs-ui/demos/pages/widgets.js +++ b/oojs/oojs-ui/demos/pages/widgets.js @@ -6,6 +6,7 @@ horizontalDragItems = [], verticalDragItems = [], verticalHandledDragItems = [], + $overlay = $( '<div>' ).addClass( 'demo-overlay' ).attr( 'id', 'demo-overlay' ), $demo = demo.$element; for ( i = 0; i <= 12; i++ ) { @@ -59,7 +60,8 @@ fieldsets = [ new OO.ui.FieldsetLayout( { - label: 'Simple buttons', + id: 'demo-section-buttons', + label: 'Buttons', items: [ new OO.ui.FieldLayout( new OO.ui.ButtonWidget( { label: 'Normal' } ), @@ -84,7 +86,7 @@ flags: [ 'constructive' ] } ), { - label: 'ButtonWidget (constructive, deprecated in MediaWiki theme)\u200E', + label: 'ButtonWidget (constructive, deprecated in WikimediaUI theme)\u200E', align: 'top' } ), @@ -114,7 +116,7 @@ flags: [ 'primary', 'constructive' ] } ), { - label: 'ButtonWidget (primary, constructive, deprecated in MediaWiki theme)\u200E', + label: 'ButtonWidget (primary, constructive, deprecated in WikimediaUI theme)\u200E', align: 'top' } ), @@ -205,6 +207,17 @@ ), new OO.ui.FieldLayout( new OO.ui.ButtonWidget( { + label: 'Accesskey: H', + accessKey: 'h' + } ), + { + label: 'ButtonWidget (with accesskey)\u200E', + align: 'top', + help: new OO.ui.HtmlSnippet( 'Notice: Using `accesskey` might <a href="http://webaim.org/techniques/keyboard/accesskey" target="_blank">negatively impact screen readers</a>!' ) + } + ), + new OO.ui.FieldLayout( + new OO.ui.ButtonWidget( { icon: 'help', title: 'Icon only, framed' } ), @@ -284,7 +297,7 @@ new OO.ui.ButtonWidget( { framed: false, flags: [ 'destructive' ], - icon: 'remove', + icon: 'trash', label: 'Destructive' } ), { @@ -351,10 +364,95 @@ label: 'ButtonWidget (frameless, indicator)\u200E', align: 'top' } + ), + new OO.ui.FieldLayout( + new OO.ui.ButtonInputWidget( { + label: 'Submit the form', + type: 'submit', + flags: [ 'primary', 'progressive' ], + useInputTag: true + } ), + { + align: 'top', + label: 'ButtonInputWidget (using <input>)\u200E' + } + ), + new OO.ui.FieldLayout( + new OO.ui.ButtonInputWidget( { + label: 'Another button', + type: 'button' + } ), + { + align: 'top', + label: 'ButtonInputWidget (using <button>)\u200E' + } + ), + new OO.ui.FieldLayout( + new OO.ui.ButtonInputWidget( { + label: 'Accesskey: I', + accessKey: 'i' + } ), + { + label: 'ButtonInputWidget (with accesskey)\u200E', + align: 'top', + help: new OO.ui.HtmlSnippet( 'Notice: Using `accesskey` might <a href="http://webaim.org/techniques/keyboard/accesskey" target="_blank">negatively impact screen readers</a>!' ) + } + ), + new OO.ui.FieldLayout( + new OO.ui.ButtonInputWidget( { + framed: false, + label: 'Another button', + type: 'button' + } ), + { + align: 'top', + label: 'ButtonInputWidget (frameless)\u200E' + } + ), + new OO.ui.FieldLayout( + new OO.ui.ButtonInputWidget( { + framed: false, + label: 'Another button', + type: 'button', + useInputTag: true + } ), + { + align: 'top', + label: 'ButtonInputWidget (frameless, using <input>)\u200E' + } + ), + new OO.ui.FieldLayout( + new OO.ui.ToggleButtonWidget( { label: 'Toggle' } ), + { + label: 'ToggleButtonWidget', + align: 'top' + } + ), + new OO.ui.FieldLayout( + new OO.ui.ToggleButtonWidget( { label: 'Toggle', value: true } ), + { + label: 'ToggleButtonWidget (initially active)\u200E', + align: 'top' + } + ), + new OO.ui.FieldLayout( + new OO.ui.ToggleButtonWidget( { icon: 'next' } ), + { + label: 'ToggleButtonWidget (icon only)\u200E', + align: 'top' + } + ), + new OO.ui.FieldLayout( + new OO.ui.ToggleButtonWidget( { icon: 'next', value: true } ), + { + label: 'ToggleButtonWidget (icon only, initially active)\u200E', + align: 'top' + } ) ] } ), new OO.ui.FieldsetLayout( { + id: 'demo-section-button-sets', label: 'Button sets', items: [ new OO.ui.FieldLayout( @@ -508,10 +606,36 @@ label: 'ButtonSelectWidget (disabled items)\u200E', align: 'top' } + ), + new OO.ui.FieldLayout( + new OO.ui.ButtonSelectWidget( { + items: [ + new OO.ui.ButtonOptionWidget( { + data: 'a', + label: 'Accesskey: J', + accessKey: 'j' + } ), + new OO.ui.ButtonOptionWidget( { + data: 'b', + label: 'Accesskey: K', + accessKey: 'k' + } ), + new OO.ui.ButtonOptionWidget( { + data: 'c', + label: 'Accesskey: L', + accessKey: 'l' + } ) + ] + } ), + { + label: 'ButtonSelectWidget (with accesskeys)\u200E', + align: 'top' + } ) ] } ), new OO.ui.FieldsetLayout( { + id: 'demo-section-button-showcase', label: 'Button style showcase', items: [ new OO.ui.FieldLayout( @@ -523,7 +647,270 @@ ] } ), new OO.ui.FieldsetLayout( { - label: 'Form widgets', + id: 'demo-section-inputs', + label: 'Inputs: TextInput, TextInput (multiline), SearchInput, NumberInput', + items: [ + new OO.ui.FieldLayout( + new OO.ui.TextInputWidget( { value: 'Text input' } ), + { + label: 'TextInputWidget\u200E', + align: 'top' + } + ), + new OO.ui.FieldLayout( + new OO.ui.TextInputWidget( { icon: 'help' } ), + { + label: 'TextInputWidget (icon)\u200E', + align: 'top' + } + ), + new OO.ui.FieldLayout( + new OO.ui.TextInputWidget( { + required: true, + validate: 'non-empty' + } ), + { + label: 'TextInputWidget (required)\u200E', + align: 'top' + } + ), + new OO.ui.FieldLayout( + new OO.ui.TextInputWidget( { + validate: function ( value ) { + return value.length % 2 === 0; + } + } ), + { + label: 'TextInputWidget (only allows even number of characters)\u200E', + align: 'top' + } + ), + new OO.ui.FieldLayout( + new OO.ui.TextInputWidget( { placeholder: 'Placeholder' } ), + { + label: 'TextInputWidget (placeholder)\u200E', + align: 'top' + } + ), + new OO.ui.FieldLayout( + new OO.ui.TextInputWidget( { + value: 'Title attribute', + title: 'Title attribute with more information about me.' + } ), + { + label: 'TextInputWidget (with title)\u200E', + align: 'top' + } + ), + new OO.ui.FieldLayout( + new OO.ui.TextInputWidget( { + value: 'Readonly', + readOnly: true + } ), + { + label: 'TextInputWidget (readonly)\u200E', + align: 'top' + } + ), + new OO.ui.FieldLayout( + new OO.ui.TextInputWidget( { + value: 'Disabled', + disabled: true + } ), + { + label: 'TextInputWidget (disabled)\u200E', + align: 'top' + } + ), + new OO.ui.FieldLayout( + new OO.ui.TextInputWidget( { + multiline: true, + value: 'Multiline\nMultiline' + } ), + { + label: 'TextInputWidget (multiline)\u200E', + align: 'top' + } + ), + new OO.ui.FieldLayout( + new OO.ui.TextInputWidget( { + multiline: true, + rows: 15, + value: 'Multiline\nMultiline' + } ), + { + label: 'TextInputWidget (multiline, rows=15)\u200E', + align: 'top' + } + ), + new OO.ui.FieldLayout( + new OO.ui.TextInputWidget( { + multiline: true, + autosize: true, + value: 'Autosize\nAutosize\nAutosize\nAutosize' + } ), + { + label: 'TextInputWidget (autosize)\u200E', + align: 'top' + } + ), + new OO.ui.FieldLayout( + new OO.ui.TextInputWidget( { + multiline: true, + rows: 10, + autosize: true, + value: 'Autosize\nAutosize\nAutosize\nAutosize' + } ), + { + label: 'TextInputWidget (autosize, rows=10)\u200E', + align: 'top' + } + ), + new OO.ui.FieldLayout( + new OO.ui.TextInputWidget( { + multiline: true, + autosize: true, + icon: 'tag', + indicator: 'alert', + label: 'Inline label', + value: 'Autosize\nAutosize\nAutosize\nAutosize' + } ), + { + label: 'TextInputWidget (autosize, icon, indicator, label)\u200E', + align: 'top' + } + ), + new OO.ui.FieldLayout( + new OO.ui.TextInputWidget( { + value: 'Text input with label', + label: 'Inline label' + } ), + { + label: 'TextInputWidget (label)\u200E', + align: 'top' + } + ), + new OO.ui.FieldLayout( + new OO.ui.TextInputWidget( { + value: 'Text input with label', + label: 'Inline label', + labelPosition: 'before' + } ), + { + label: 'TextInputWidget (label[position=before])\u200E', + align: 'top' + } + ), + new OO.ui.FieldLayout( + new OO.ui.TextInputWidget( { + icon: 'tag', + indicator: 'alert', + value: 'Text input with label', + label: 'Inline label' + } ), + { + label: 'TextInputWidget (icon, indicator, label)\u200E', + align: 'top' + } + ), + new OO.ui.FieldLayout( + new OO.ui.TextInputWidget( { + icon: 'tag', + indicator: 'alert', + value: 'Text input with label', + label: 'Inline label', + labelPosition: 'before' + } ), + { + label: 'TextInputWidget (icon, indicator, label[position=before])\u200E', + align: 'top' + } + ), + new OO.ui.FieldLayout( + new OO.ui.TextInputWidget( { + value: 'Disabled', + icon: 'tag', + indicator: 'alert', + label: 'Inline label', + disabled: true + } ), + { + label: 'TextInputWidget (icon, indicator, label, disabled)\u200E', + align: 'top' + } + ), + new OO.ui.FieldLayout( + new OO.ui.TextInputWidget( { + value: 'Accesskey: S', + accessKey: 's' + } ), + { + label: 'TextInputWidget (with accesskey)\u200E', + align: 'top', + help: new OO.ui.HtmlSnippet( 'Notice: Using `accesskey` might <a href="http://webaim.org/techniques/keyboard/accesskey" target="_blank">negatively impact screen readers</a>!' ) + } + ), + new OO.ui.FieldLayout( + new OO.ui.SearchInputWidget(), + { + label: 'SearchInputWidget (type=search)\u200E', + align: 'top' + } + ), + new OO.ui.FieldLayout( + new OO.ui.SearchInputWidget( { disabled: true } ), + { + label: 'SearchInputWidget (disabled)\u200E', + align: 'top' + } + ), + new OO.ui.FieldLayout( + new OO.ui.SearchInputWidget( { disabled: true, value: 'test' } ), + { + label: 'SearchInputWidget (disabled, filled)\u200E', + align: 'top' + } + ), + new OO.ui.FieldLayout( + new OO.ui.NumberInputWidget(), + { + label: 'NumberInputWidget', + align: 'top' + } + ), + new OO.ui.FieldLayout( + new OO.ui.NumberInputWidget( { disabled: true } ), + { + label: 'NumberInputWidget (disabled)', + align: 'top' + } + ), + new OO.ui.FieldLayout( + new OO.ui.NumberInputWidget( { min: 1, max: 5, isInteger: true } ), + { + label: 'NumberInputWidget (1–5, ints only)', + align: 'top' + } + ), + new OO.ui.FieldLayout( + new OO.ui.NumberInputWidget( { min: 0, max: 1, step: 0.1, pageStep: 0.25 } ), + { + label: 'NumberInputWidget (0–1, step by .1, page by .25)', + align: 'top' + } + ), + new OO.ui.FieldLayout( + new OO.ui.NumberInputWidget( { showButtons: false } ), + { + label: 'NumberInputWidget (no buttons)', + align: 'top' + } + ) + ] + } ), + new OO.ui.FieldsetLayout( { + id: 'demo-section-inputs-binary', + label: 'Checkbox, Radio & ToggleSwitch', items: [ new OO.ui.FieldLayout( new OO.ui.CheckboxInputWidget( { @@ -667,38 +1054,28 @@ } ), new OO.ui.FieldLayout( - new OO.ui.NumberInputWidget(), + new OO.ui.RadioSelectWidget( { + items: [ + new OO.ui.RadioOptionWidget( { + data: 'a', + label: 'Accesskey: M', + accessKey: 'm' + } ), + new OO.ui.RadioOptionWidget( { + data: 'b', + label: 'Accesskey: N', + accessKey: 'n' + } ), + new OO.ui.RadioOptionWidget( { + data: 'c', + label: 'Accesskey: O', + accessKey: 'o' + } ) + ] + } ), { - label: 'NumberInputWidget', - align: 'top' - } - ), - new OO.ui.FieldLayout( - new OO.ui.NumberInputWidget( { disabled: true } ), - { - label: 'NumberInputWidget (disabled)', - align: 'top' - } - ), - new OO.ui.FieldLayout( - new OO.ui.NumberInputWidget( { min: 1, max: 5, isInteger: true } ), - { - label: 'NumberInputWidget (1–5, ints only)', - align: 'top' - } - ), - new OO.ui.FieldLayout( - new OO.ui.NumberInputWidget( { min: 0, max: 1, step: 0.1, pageStep: 0.25 } ), - { - label: 'NumberInputWidget (0–1, step by .1, page by .25)', - align: 'top' - } - ), - new OO.ui.FieldLayout( - new OO.ui.NumberInputWidget( { showButtons: false } ), - { - label: 'NumberInputWidget (no buttons)', - align: 'top' + align: 'top', + label: 'RadioSelectWidget (with accesskeys)\u200E' } ), new OO.ui.FieldLayout( @@ -721,286 +1098,13 @@ label: 'ToggleSwitchWidget (disabled, checked)\u200E', align: 'top' } - ), - new OO.ui.FieldLayout( - new OO.ui.ToggleButtonWidget( { label: 'Toggle' } ), - { - label: 'ToggleButtonWidget', - align: 'top' - } - ), - new OO.ui.FieldLayout( - new OO.ui.ToggleButtonWidget( { label: 'Toggle', value: true } ), - { - label: 'ToggleButtonWidget (initially active)\u200E', - align: 'top' - } - ), - new OO.ui.FieldLayout( - new OO.ui.ToggleButtonWidget( { icon: 'next' } ), - { - label: 'ToggleButtonWidget (icon only)\u200E', - align: 'top' - } - ), - new OO.ui.FieldLayout( - new OO.ui.ToggleButtonWidget( { icon: 'next', value: true } ), - { - label: 'ToggleButtonWidget (icon only, initially active)\u200E', - align: 'top' - } - ), - new OO.ui.FieldLayout( - new OO.ui.TextInputWidget( { value: 'Text input' } ), - { - label: 'TextInputWidget\u200E', - align: 'top' - } - ), - new OO.ui.FieldLayout( - new OO.ui.TextInputWidget( { icon: 'help' } ), - { - label: 'TextInputWidget (icon)\u200E', - align: 'top' - } - ), - new OO.ui.FieldLayout( - new OO.ui.TextInputWidget( { - required: true, - validate: 'non-empty' - } ), - { - label: 'TextInputWidget (required)\u200E', - align: 'top' - } - ), - new OO.ui.FieldLayout( - new OO.ui.TextInputWidget( { - validate: function ( value ) { - return value.length % 2 === 0; - } - } ), - { - label: 'TextInputWidget (only allows even number of characters)\u200E', - align: 'top' - } - ), - new OO.ui.FieldLayout( - new OO.ui.TextInputWidget( { placeholder: 'Placeholder' } ), - { - label: 'TextInputWidget (placeholder)\u200E', - align: 'top' - } - ), - new OO.ui.FieldLayout( - new OO.ui.TextInputWidget( { type: 'number' } ), - { - label: 'TextInputWidget (type=number)\u200E', - align: 'top' - } - ), - new OO.ui.FieldLayout( - new OO.ui.TextInputWidget( { - value: 'Readonly', - readOnly: true - } ), - { - label: 'TextInputWidget (readonly)\u200E', - align: 'top' - } - ), - new OO.ui.FieldLayout( - new OO.ui.TextInputWidget( { - value: 'Disabled', - disabled: true - } ), - { - label: 'TextInputWidget (disabled)\u200E', - align: 'top' - } - ), - new OO.ui.FieldLayout( - new OO.ui.SearchInputWidget(), - { - label: 'SearchInputWidget (type=search)\u200E', - align: 'top' - } - ), - new OO.ui.FieldLayout( - new OO.ui.SearchInputWidget( { disabled: true } ), - { - label: 'SearchInputWidget (disabled)\u200E', - align: 'top' - } - ), - new OO.ui.FieldLayout( - new OO.ui.SearchInputWidget( { disabled: true, value: 'test' } ), - { - label: 'SearchInputWidget (disabled, filled)\u200E', - align: 'top' - } - ), - new OO.ui.FieldLayout( - new OO.ui.TextInputWidget( { - multiline: true, - value: 'Multiline\nMultiline' - } ), - { - label: 'TextInputWidget (multiline)\u200E', - align: 'top' - } - ), - new OO.ui.FieldLayout( - new OO.ui.TextInputWidget( { - multiline: true, - rows: 15, - value: 'Multiline\nMultiline' - } ), - { - label: 'TextInputWidget (multiline, rows=15)\u200E', - align: 'top' - } - ), - new OO.ui.FieldLayout( - new OO.ui.TextInputWidget( { - multiline: true, - autosize: true, - value: 'Autosize\nAutosize\nAutosize\nAutosize' - } ), - { - label: 'TextInputWidget (autosize)\u200E', - align: 'top' - } - ), - new OO.ui.FieldLayout( - new OO.ui.TextInputWidget( { - multiline: true, - rows: 10, - autosize: true, - value: 'Autosize\nAutosize\nAutosize\nAutosize' - } ), - { - label: 'TextInputWidget (autosize, rows=10)\u200E', - align: 'top' - } - ), - new OO.ui.FieldLayout( - new OO.ui.TextInputWidget( { - multiline: true, - autosize: true, - icon: 'tag', - indicator: 'alert', - label: 'Inline label', - value: 'Autosize\nAutosize\nAutosize\nAutosize' - } ), - { - label: 'TextInputWidget (autosize, icon, indicator, label)\u200E', - align: 'top' - } - ), - new OO.ui.FieldLayout( - new OO.ui.TextInputWidget( { - icon: 'tag', - indicator: 'alert', - value: 'Text input with label', - label: 'Inline label' - } ), - { - label: 'TextInputWidget (icon, indicator, label)\u200E', - align: 'top' - } - ), - new OO.ui.FieldLayout( - new OO.ui.TextInputWidget( { - value: 'Disabled', - icon: 'tag', - indicator: 'alert', - label: 'Inline label', - disabled: true - } ), - { - label: 'TextInputWidget (icon, indicator, label, disabled)\u200E', - align: 'top' - } - ), - new OO.ui.FieldLayout( - new OO.ui.TextInputWidget( { - value: 'Title attribute', - title: 'Title attribute with more information about me.' - } ), - { - label: 'TextInputWidget (with title)\u200E', - align: 'top' - } - ), - new OO.ui.FieldLayout( - new OO.ui.SelectFileWidget( {} ), - { - label: 'SelectFileWidget\u200E', - align: 'top' - } - ), - new OO.ui.FieldLayout( - new OO.ui.SelectFileWidget( { accept: [ 'image/png', 'image/jpeg' ] } ), - { - label: 'SelectFileWidget (accept PNG and JPEG)\u200E', - align: 'top' - } - ), - new OO.ui.FieldLayout( - new OO.ui.SelectFileWidget( { - icon: 'tag', - indicator: 'alert' - } ), - { - label: 'SelectFileWidget (icon, indicator)\u200E', - align: 'top' - } - ), - new OO.ui.FieldLayout( - new OO.ui.SelectFileWidget( { - icon: 'tag', - indicator: 'alert', - disabled: true - } ), - { - label: 'SelectFileWidget (disabled)\u200E', - align: 'top' - } - ), - new OO.ui.FieldLayout( - new Demo.UnsupportedSelectFileWidget(), - { - label: 'SelectFileWidget (no browser support)\u200E', - align: 'top' - } - ), - new OO.ui.FieldLayout( - new OO.ui.SelectFileWidget( { showDropTarget: true } ), - { - label: 'SelectFileWidget (with drop target)\u200E', - align: 'top' - } - ), - new OO.ui.FieldLayout( - new OO.ui.SelectFileWidget( { - showDropTarget: true, - disabled: true - } ), - { - label: 'SelectFileWidget (with drop target, disabled)\u200E', - align: 'top' - } - ), - new OO.ui.FieldLayout( - new Demo.UnsupportedSelectFileWidget( { - showDropTarget: true - } ), - { - label: 'SelectFileWidget (with drop target, no browser support)\u200E', - align: 'top' - } - ), + ) + ] + } ), + new OO.ui.FieldsetLayout( { + id: 'demo-section-dropdown', + label: 'Dropdown', + items: [ new OO.ui.FieldLayout( new OO.ui.DropdownWidget( { label: 'Select one', @@ -1138,7 +1242,7 @@ new OO.ui.FieldLayout( new OO.ui.DropdownWidget( { label: 'Select one', - $overlay: $( '<div>' ).appendTo( 'body' ).css( { position: 'absolute', top: 0, left: 0 } ), + $overlay: $overlay, menu: { items: [ new OO.ui.MenuOptionWidget( { @@ -1193,6 +1297,33 @@ { label: 'DropdownWidget (does not close on choose)\u200E', align: 'top' + } + ), + new OO.ui.FieldLayout( + new OO.ui.DropdownWidget( { + menu: { + items: [ + new OO.ui.MenuOptionWidget( { + data: 'a', + label: 'Accesskey: P', + accessKey: 'p' + } ), + new OO.ui.MenuOptionWidget( { + data: 'b', + label: 'Accesskey: Q', + accessKey: 'q' + } ), + new OO.ui.MenuOptionWidget( { + data: 'c', + label: 'Accesskey: R', + accessKey: 'r' + } ) + ] + } + } ), + { + align: 'top', + label: 'DropdownWidget (with accesskeys)\u200E' } ), new OO.ui.FieldLayout( @@ -1304,7 +1435,13 @@ label: 'DropdownInputWidget (long)\u200E', align: 'top' } - ), + ) + ] + } ), + new OO.ui.FieldsetLayout( { + id: 'demo-section-comboBox', + label: 'ComboBox', + items: [ new OO.ui.FieldLayout( new OO.ui.ComboBoxInputWidget( { options: [ @@ -1395,7 +1532,87 @@ label: 'ComboBoxInputWidget (empty)\u200E', align: 'top' } + ) + ] + } ), + new OO.ui.FieldsetLayout( { + id: 'demo-section-selectFile', + label: 'SelectFile', + items: [ + new OO.ui.FieldLayout( + new OO.ui.SelectFileWidget( {} ), + { + label: 'SelectFileWidget\u200E', + align: 'top' + } ), + new OO.ui.FieldLayout( + new OO.ui.SelectFileWidget( { accept: [ 'image/png', 'image/jpeg' ] } ), + { + label: 'SelectFileWidget (accept PNG and JPEG)\u200E', + align: 'top' + } + ), + new OO.ui.FieldLayout( + new OO.ui.SelectFileWidget( { + icon: 'tag', + indicator: 'alert' + } ), + { + label: 'SelectFileWidget (icon, indicator)\u200E', + align: 'top' + } + ), + new OO.ui.FieldLayout( + new OO.ui.SelectFileWidget( { + icon: 'tag', + indicator: 'alert', + disabled: true + } ), + { + label: 'SelectFileWidget (disabled)\u200E', + align: 'top' + } + ), + new OO.ui.FieldLayout( + new Demo.UnsupportedSelectFileWidget(), + { + label: 'SelectFileWidget (no browser support)\u200E', + align: 'top' + } + ), + new OO.ui.FieldLayout( + new OO.ui.SelectFileWidget( { showDropTarget: true } ), + { + label: 'SelectFileWidget (with drop target)\u200E', + align: 'top' + } + ), + new OO.ui.FieldLayout( + new OO.ui.SelectFileWidget( { + showDropTarget: true, + disabled: true + } ), + { + label: 'SelectFileWidget (with drop target, disabled)\u200E', + align: 'top' + } + ), + new OO.ui.FieldLayout( + new Demo.UnsupportedSelectFileWidget( { + showDropTarget: true + } ), + { + label: 'SelectFileWidget (with drop target, no browser support)\u200E', + align: 'top' + } + ) + ] + } ), + new OO.ui.FieldsetLayout( { + id: 'demo-section-tagMultiselect', + label: 'TagMultiselect, MenuTagMultiselect, CapsuleMultiselect', + items: [ new OO.ui.FieldLayout( new OO.ui.TagMultiselectWidget( { placeholder: 'Add tags', @@ -1463,6 +1680,33 @@ ), new OO.ui.FieldLayout( new OO.ui.MenuTagMultiselectWidget( { + selected: [ + { data: 'foo', label: 'Label for foo' }, + { data: 'bar', label: 'Label for bar' } + ], + options: [ + { data: 'foo', label: 'Label for foo' }, + { data: 'bar', label: 'Label for bar' }, + { data: 'baz', label: 'Label for baz' } + ] + } ), + { + label: 'MenuTagMultiselectWidget (initially selected, preset options)', + align: 'top' + } + ), + new OO.ui.FieldLayout( + new OO.ui.MenuTagMultiselectWidget( { + selected: [ 'foo', 'bar' ], + allowArbitrary: true + } ), + { + label: 'MenuTagMultiselectWidget (initially selected, allowArbitrary)', + align: 'top' + } + ), + new OO.ui.FieldLayout( + new OO.ui.MenuTagMultiselectWidget( { allowArbitrary: false, options: [ { data: 'abc', label: 'Label for abc' }, @@ -1510,7 +1754,7 @@ ), new OO.ui.FieldLayout( new OO.ui.CapsuleMultiselectWidget( { - placeholder: 'Type like a cat...', + placeholder: 'Type like a cat…', menu: { items: [ new OO.ui.MenuOptionWidget( { data: 'abc', label: 'Label for abc' } ), @@ -1627,340 +1871,35 @@ label: 'CapsuleMultiselectWidget with NumberInputWidget popup\u200E', align: 'top' } - ), + ) + ] + } ), + new OO.ui.FieldsetLayout( { + id: 'demo-section-lookupElement', + label: 'LookupElement', + items: [ new OO.ui.FieldLayout( - new OO.ui.ButtonInputWidget( { - label: 'Submit the form', - type: 'submit', - flags: [ 'primary', 'progressive' ], - useInputTag: true - } ), + new Demo.NumberLookupTextInputWidget(), { - align: 'top', - label: 'ButtonInputWidget (using <input>)\u200E' - } - ), - new OO.ui.FieldLayout( - new OO.ui.ButtonInputWidget( { - label: 'Another button', - type: 'button' - } ), - { - align: 'top', - label: 'ButtonInputWidget (using <button>)\u200E' - } - ), - new OO.ui.FieldLayout( - new OO.ui.ButtonInputWidget( { - framed: false, - label: 'Another button', - type: 'button' - } ), - { - align: 'top', - label: 'ButtonInputWidget (frameless)\u200E' - } - ), - new OO.ui.FieldLayout( - new OO.ui.ButtonInputWidget( { - framed: false, - label: 'Another button', - type: 'button', - useInputTag: true - } ), - { - align: 'top', - label: 'ButtonInputWidget (frameless, using <input>)\u200E' - } - ), - new OO.ui.FieldLayout( - new OO.ui.ButtonWidget( { - label: 'Accesskey: H', - accessKey: 'h' - } ), - { - label: 'ButtonWidget (with accesskey)\u200E', + label: 'LookupElement (try inputting an integer)\u200E', align: 'top' } ), new OO.ui.FieldLayout( - new OO.ui.ButtonInputWidget( { - label: 'Accesskey: I', - accessKey: 'i' + new Demo.NumberLookupTextInputWidget( { + highlightFirst: false } ), { - label: 'ButtonInputWidget (with accesskey)\u200E', - align: 'top' - } - ), - new OO.ui.FieldLayout( - new OO.ui.ButtonSelectWidget( { - items: [ - new OO.ui.ButtonOptionWidget( { - data: 'a', - label: 'Accesskey: J', - accessKey: 'j' - } ), - new OO.ui.ButtonOptionWidget( { - data: 'b', - label: 'Accesskey: K', - accessKey: 'k' - } ), - new OO.ui.ButtonOptionWidget( { - data: 'c', - label: 'Accesskey: L', - accessKey: 'l' - } ) - ] - } ), - { - label: 'ButtonSelectWidget (with accesskeys)\u200E', - align: 'top' - } - ), - new OO.ui.FieldLayout( - new OO.ui.RadioSelectWidget( { - items: [ - new OO.ui.RadioOptionWidget( { - data: 'a', - label: 'Accesskey: M', - accessKey: 'm' - } ), - new OO.ui.RadioOptionWidget( { - data: 'b', - label: 'Accesskey: N', - accessKey: 'n' - } ), - new OO.ui.RadioOptionWidget( { - data: 'c', - label: 'Accesskey: O', - accessKey: 'o' - } ) - ] - } ), - { - align: 'top', - label: 'RadioSelectWidget (with accesskeys)\u200E' - } - ), - new OO.ui.FieldLayout( - new OO.ui.DropdownWidget( { - menu: { - items: [ - new OO.ui.MenuOptionWidget( { - data: 'a', - label: 'Accesskey: P', - accessKey: 'p' - } ), - new OO.ui.MenuOptionWidget( { - data: 'b', - label: 'Accesskey: Q', - accessKey: 'q' - } ), - new OO.ui.MenuOptionWidget( { - data: 'c', - label: 'Accesskey: R', - accessKey: 'r' - } ) - ] - } - } ), - { - align: 'top', - label: 'DropdownWidget (with accesskeys)\u200E' - } - ), - new OO.ui.FieldLayout( - new OO.ui.TextInputWidget( { - value: 'Accesskey: S', - accessKey: 's' - } ), - { - label: 'TextInputWidget (with accesskey)\u200E', + label: 'LookupElement without highlighting 1st term (try inputting an integer)\u200E', align: 'top' } ) ] } ), new OO.ui.FieldsetLayout( { - label: 'HorizontalLayout', + id: 'demo-section-popupButton', + label: 'PopupButton', items: [ - new OO.ui.FieldLayout( - new OO.ui.Widget( { - content: [ new OO.ui.HorizontalLayout( { - items: [ - new OO.ui.ButtonWidget( { label: 'Button' } ), - new OO.ui.ButtonGroupWidget( { items: [ - new OO.ui.ToggleButtonWidget( { label: 'A' } ), - new OO.ui.ToggleButtonWidget( { label: 'B' } ) - ] } ), - new OO.ui.ButtonInputWidget( { label: 'ButtonInput' } ), - new OO.ui.TextInputWidget( { value: 'TextInput' } ), - new OO.ui.DropdownInputWidget( { options: [ - { - label: 'DropdownInput', - data: null - } - ] } ), - new OO.ui.CheckboxInputWidget( { selected: true } ), - new OO.ui.RadioInputWidget( { selected: true } ), - new OO.ui.LabelWidget( { label: 'Label' } ) - ] - } ) ] - } ), - { - label: 'Multiple widgets shown as a single line, ' + - 'as used in compact forms or in parts of a bigger widget.', - align: 'top' - } - ) - ] - } ), - new OO.ui.FieldsetLayout( { - label: 'Draggable', - items: [ - new OO.ui.FieldLayout( - new Demo.DraggableGroupWidget( { - orientation: 'horizontal', - items: horizontalDragItems - } ), - { - label: 'DraggableGroupWidget (horizontal)\u200E', - align: 'top' - } - ), - new OO.ui.FieldLayout( - new Demo.DraggableGroupWidget( { - items: verticalDragItems - } ), - { - label: 'DraggableGroupWidget (vertical)\u200E', - align: 'top' - } - ), - new OO.ui.FieldLayout( - new Demo.DraggableGroupWidget( { - items: verticalHandledDragItems - } ), - { - label: 'DraggableGroupWidget with handles (vertical)\u200E', - align: 'top' - } - ) - ] - } ), - new OO.ui.FieldsetLayout( { - label: 'Other widgets', - items: [ - new OO.ui.FieldLayout( - new OO.ui.IconWidget( { - icon: 'search', - title: 'Search icon' - } ), - { - label: 'IconWidget (normal)\u200E', - align: 'top' - } - ), - new OO.ui.FieldLayout( - new OO.ui.IconWidget( { - icon: 'remove', - flags: 'destructive', - title: 'Remove icon' - } ), - { - label: 'IconWidget (flagged)\u200E', - align: 'top' - } - ), - new OO.ui.FieldLayout( - new OO.ui.IconWidget( { - icon: 'search', - title: 'Search icon', - disabled: true - } ), - { - label: 'IconWidget (disabled)\u200E', - align: 'top' - } - ), - new OO.ui.FieldLayout( - new OO.ui.IndicatorWidget( { - indicator: 'alert', - title: 'Required indicator' - } ), - { - label: 'IndicatorWidget (normal)\u200E', - align: 'top' - } - ), - new OO.ui.FieldLayout( - new OO.ui.IndicatorWidget( { - indicator: 'alert', - title: 'Required indicator', - disabled: true - } ), - { - label: 'IndicatorWidget (disabled)\u200E', - align: 'top' - } - ), - new OO.ui.FieldLayout( - new OO.ui.LabelWidget( { - label: 'Label' - } ), - { - label: 'LabelWidget (normal)\u200E', - align: 'top' - } - ), - new OO.ui.FieldLayout( - new OO.ui.LabelWidget( { - label: 'Label', - disabled: true - } ), - { - label: 'LabelWidget (disabled)\u200E', - align: 'top' - } - ), - new OO.ui.FieldLayout( - new OO.ui.LabelWidget( { - label: new OO.ui.HtmlSnippet( '<b>Fancy</b> <i>text</i> <u>formatting</u>!' ) - } ), - { - label: 'LabelWidget (with HTML)\u200E', - align: 'top' - } - ), - new OO.ui.FieldLayout( - labelForTextInput, - { - label: 'LabelWidget (with an associated TextInputWidget)\u200E', - align: 'top' - } - ), - new OO.ui.FieldLayout( - textInputForLabel, - { - label: 'TextInputWidget (with an associated label)\u200E', - align: 'top' - } - ), - new OO.ui.FieldLayout( - labelForRadioSelectInput, - { - label: 'LabelWidget (with an associated RadioSelectInputWidget)\u200E', - align: 'top' - } - ), - new OO.ui.FieldLayout( - radioSelectInputForLabel, - { - label: 'RadioSelectInputWidget (with an associated label)\u200E', - align: 'top' - } - ), new OO.ui.FieldLayout( new OO.ui.PopupButtonWidget( { icon: 'info', @@ -2164,30 +2103,87 @@ popup: { $content: $( '<p>' ).text( loremIpsum ), padded: true, - anchor: false + anchor: false, + align: 'center' } } ), { - label: 'PopupButtonWidget (no anchor)\u200E', + label: 'PopupButtonWidget (no anchor, align: center)\u200E', align: 'top' } ), new OO.ui.FieldLayout( - new Demo.NumberLookupTextInputWidget(), - { - label: 'LookupElement (try inputting an integer)\u200E', - align: 'top' - } - ), - new OO.ui.FieldLayout( - new Demo.NumberLookupTextInputWidget( { - highlightFirst: false + new OO.ui.PopupButtonWidget( { + icon: 'menu', + label: 'Options', + popup: { + $content: $( '<p>' ).text( loremIpsum ), + padded: true, + anchor: false, + align: 'forwards' + } } ), { - label: 'LookupElement without highlighting 1st term (try inputting an integer)\u200E', + label: 'PopupButtonWidget (no anchor, align: forwards)\u200E', align: 'top' } ), + new OO.ui.FieldLayout( + new OO.ui.PopupButtonWidget( { + icon: 'menu', + label: 'Options', + popup: { + $content: $( '<p>' ).text( loremIpsum ), + padded: true, + anchor: false, + align: 'backwards' + } + } ), + { + label: 'PopupButtonWidget (no anchor, align: backwards)\u200E', + align: 'top' + } + ) + ] + } ), + new OO.ui.FieldsetLayout( { + id: 'demo-section-draggable', + label: 'Draggable', + items: [ + new OO.ui.FieldLayout( + new Demo.DraggableGroupWidget( { + orientation: 'horizontal', + items: horizontalDragItems + } ), + { + label: 'DraggableGroupWidget (horizontal)\u200E', + align: 'top' + } + ), + new OO.ui.FieldLayout( + new Demo.DraggableGroupWidget( { + items: verticalDragItems + } ), + { + label: 'DraggableGroupWidget (vertical)\u200E', + align: 'top' + } + ), + new OO.ui.FieldLayout( + new Demo.DraggableGroupWidget( { + items: verticalHandledDragItems + } ), + { + label: 'DraggableGroupWidget with handles (vertical)\u200E', + align: 'top' + } + ) + ] + } ), + new OO.ui.FieldsetLayout( { + id: 'demo-section-progressBar', + label: 'Progress bar', + items: [ new OO.ui.FieldLayout( new OO.ui.ProgressBarWidget( { progress: 33 @@ -2199,6 +2195,7 @@ ), new OO.ui.FieldLayout( new OO.ui.ProgressBarWidget( { + progress: 50, disabled: true } ), { @@ -2218,6 +2215,122 @@ ] } ), new OO.ui.FieldsetLayout( { + id: 'demo-section-others', + label: 'Other widgets', + items: [ + new OO.ui.FieldLayout( + new OO.ui.IconWidget( { + icon: 'search', + title: 'Search icon' + } ), + { + label: 'IconWidget (normal)\u200E', + align: 'top' + } + ), + new OO.ui.FieldLayout( + new OO.ui.IconWidget( { + icon: 'trash', + flags: 'destructive', + title: 'Remove icon' + } ), + { + label: 'IconWidget (flagged)\u200E', + align: 'top' + } + ), + new OO.ui.FieldLayout( + new OO.ui.IconWidget( { + icon: 'search', + title: 'Search icon', + disabled: true + } ), + { + label: 'IconWidget (disabled)\u200E', + align: 'top' + } + ), + new OO.ui.FieldLayout( + new OO.ui.IndicatorWidget( { + indicator: 'alert', + title: 'Required indicator' + } ), + { + label: 'IndicatorWidget (normal)\u200E', + align: 'top' + } + ), + new OO.ui.FieldLayout( + new OO.ui.IndicatorWidget( { + indicator: 'alert', + title: 'Required indicator', + disabled: true + } ), + { + label: 'IndicatorWidget (disabled)\u200E', + align: 'top' + } + ), + new OO.ui.FieldLayout( + new OO.ui.LabelWidget( { + label: 'Label' + } ), + { + label: 'LabelWidget (normal)\u200E', + align: 'top' + } + ), + new OO.ui.FieldLayout( + new OO.ui.LabelWidget( { + label: 'Label', + disabled: true + } ), + { + label: 'LabelWidget (disabled)\u200E', + align: 'top' + } + ), + new OO.ui.FieldLayout( + new OO.ui.LabelWidget( { + label: new OO.ui.HtmlSnippet( '<b>Fancy</b> <i>text</i> <u>formatting</u>!' ) + } ), + { + label: 'LabelWidget (with HTML)\u200E', + align: 'top' + } + ), + new OO.ui.FieldLayout( + labelForTextInput, + { + label: 'LabelWidget (with an associated TextInputWidget)\u200E', + align: 'top' + } + ), + new OO.ui.FieldLayout( + textInputForLabel, + { + label: 'TextInputWidget (with an associated label)\u200E', + align: 'top' + } + ), + new OO.ui.FieldLayout( + labelForRadioSelectInput, + { + label: 'LabelWidget (with an associated RadioSelectInputWidget)\u200E', + align: 'top' + } + ), + new OO.ui.FieldLayout( + radioSelectInputForLabel, + { + label: 'RadioSelectInputWidget (with an associated label)\u200E', + align: 'top' + } + ) + ] + } ), + new OO.ui.FieldsetLayout( { + id: 'demo-section-fieldLayouts', label: 'Field layouts', icon: 'tag', help: loremIpsum, @@ -2410,11 +2523,47 @@ ) ] } ), + new OO.ui.FieldsetLayout( { + id: 'demo-section-horizontalLayout', + label: 'HorizontalLayout', + items: [ + new OO.ui.FieldLayout( + new OO.ui.Widget( { + content: [ new OO.ui.HorizontalLayout( { + items: [ + new OO.ui.ButtonWidget( { label: 'Button' } ), + new OO.ui.ButtonGroupWidget( { items: [ + new OO.ui.ToggleButtonWidget( { label: 'A' } ), + new OO.ui.ToggleButtonWidget( { label: 'B' } ) + ] } ), + new OO.ui.ButtonInputWidget( { label: 'ButtonInput' } ), + new OO.ui.TextInputWidget( { value: 'TextInput' } ), + new OO.ui.DropdownInputWidget( { options: [ + { + label: 'DropdownInput', + data: null + } + ] } ), + new OO.ui.CheckboxInputWidget( { selected: true } ), + new OO.ui.RadioInputWidget( { selected: true } ), + new OO.ui.LabelWidget( { label: 'Label' } ) + ] + } ) ] + } ), + { + label: 'Multiple widgets shown as a single line, ' + + 'as used in compact forms or in parts of a bigger widget.', + align: 'top' + } + ) + ] + } ), new OO.ui.FormLayout( { method: 'GET', action: 'demos.php', items: [ new OO.ui.FieldsetLayout( { + id: 'demo-section-formLayout', label: 'Form layout (compounded example)', items: [ new OO.ui.FieldLayout( @@ -2512,6 +2661,18 @@ label: 'Remember me', align: 'inline' } + ), + new OO.ui.FieldLayout( + new OO.ui.HiddenInputWidget( { + name: 'hidden', + value: 'hidden value' + } ) + ), + new OO.ui.FieldLayout( + new OO.ui.ButtonInputWidget( { + type: 'submit', + label: 'Submit form' + } ) ) ] } ), @@ -2545,6 +2706,11 @@ framed: false, icon: 'tag', label: 'Random icon button' + } ), + new OO.ui.ButtonWidget( { + framed: false, + icon: 'help', + title: 'Icon only' } ) ] } ) ] @@ -2568,9 +2734,18 @@ ]; $.each( fieldsets, function ( i, fieldsetLayout ) { + var showLayoutCode = false; + + if ( + fieldsetLayout instanceof OO.ui.FormLayout || + fieldsetLayout.getLabel() === 'Field layouts' + ) { + showLayoutCode = true; + } + $.each( fieldsetLayout.getItems(), function ( j, fieldLayout ) { fieldLayout.$element.append( - demo.buildConsole( fieldLayout, 'layout', 'widget' ) + demo.buildConsole( fieldLayout, 'layout', 'widget', showLayoutCode ) ); } ); } ); @@ -2586,4 +2761,10 @@ $( fieldsets.map( function ( fieldset ) { return fieldset.$element[ 0 ]; } ) ) ) ); + + $overlay.appendTo( 'body' ); + + demo.once( 'destroy', function () { + $overlay.remove(); + } ); }; diff --git a/oojs/oojs-ui/demos/pages/widgets.php b/oojs/oojs-ui/demos/pages/widgets.php index 44b6b48..d6b13db 100644 --- a/oojs/oojs-ui/demos/pages/widgets.php +++ b/oojs/oojs-ui/demos/pages/widgets.php @@ -12,11 +12,13 @@ 'padded' => true, 'framed' => true, ] ); + $demoContainer->addClasses( [ 'demo-container' ] ); $demoContainer->appendContent( new OOUI\FieldsetLayout( [ + 'id' => 'demo-section-buttons', 'infusable' => true, - 'label' => 'Simple buttons', + 'label' => 'Buttons', 'items' => [ new OOUI\FieldLayout( new OOUI\ButtonWidget( [ 'label' => 'Normal' ] ), @@ -254,9 +256,79 @@ 'align' => 'top' ] ), + new OOUI\FieldLayout( + new OOUI\ButtonInputWidget( [ + 'label' => 'Submit the form', + 'type' => 'submit', + 'flags' => [ 'primary', 'progressive' ], + 'useInputTag' => true + ] ), + [ + 'align' => 'top', + 'label' => "ButtonInputWidget (using <input>)\xE2\x80\x8E" + ] + ), + new OOUI\FieldLayout( + new OOUI\ButtonInputWidget( [ + 'label' => 'Another button', + 'type' => 'button' + ] ), + [ + 'align' => 'top', + 'label' => "ButtonInputWidget (using <button>)\xE2\x80\x8E" + ] + ), + new OOUI\FieldLayout( + new OOUI\ButtonInputWidget( [ + 'framed' => false, + 'label' => 'Another button', + 'type' => 'button' + ] ), + [ + 'align' => 'top', + 'label' => "ButtonInputWidget (frameless)\xE2\x80\x8E" + ] + ), + new OOUI\FieldLayout( + new OOUI\ButtonInputWidget( [ + 'framed' => false, + 'label' => 'Another button', + 'type' => 'button', + 'useInputTag' => true + ] ), + [ + 'align' => 'top', + 'label' => "ButtonInputWidget (frameless, using <input>)\xE2\x80\x8E" + ] + ), + new OOUI\FieldLayout( + new OOUI\ButtonWidget( [ + 'label' => 'Accesskey: H', + 'accessKey' => 'h' + ] ), + [ + 'label' => "ButtonWidget (with accesskey)\xE2\x80\x8E", + 'align' => 'top', + 'help' => new OOUI\HtmlSnippet( 'Notice: Using `accesskey` might ' . + '<a href="http://webaim.org/techniques/keyboard/accesskey" target="_blank">' . + 'negatively impact screen readers</a>!' ) + ] + ), + new OOUI\FieldLayout( + new OOUI\ButtonInputWidget( [ + 'label' => 'Accesskey: I', + 'accessKey' => 'i' + ] ), + [ + 'label' => "ButtonInputWidget (with accesskey)\xE2\x80\x8E", + 'align' => 'top' + ] + ) ] ] ) ); + $demoContainer->appendContent( new OOUI\FieldsetLayout( [ + 'id' => 'demo-section-button-sets', 'infusable' => true, 'label' => 'Button sets', 'items' => [ @@ -283,7 +355,9 @@ ) ] ] ) ); + $demoContainer->appendContent( new OOUI\FieldsetLayout( [ + 'id' => 'demo-section-button-showcase', 'infusable' => true, 'label' => 'Button style showcase', 'items' => [ @@ -293,11 +367,134 @@ 'align' => 'top', ] ) - ], + ] ] ) ); + $demoContainer->appendContent( new OOUI\FieldsetLayout( [ + 'id' => 'demo-section-inputs', 'infusable' => true, - 'label' => 'Form widgets', + 'label' => 'TextInput', + 'items' => [ + new OOUI\FieldLayout( + new OOUI\TextInputWidget( [ 'value' => 'Text input' ] ), + [ + 'label' => "TextInputWidget\xE2\x80\x8E", + 'align' => 'top' + ] + ), + new OOUI\FieldLayout( + new OOUI\TextInputWidget( [ 'icon' => 'help' ] ), + [ + 'label' => "TextInputWidget (icon)\xE2\x80\x8E", + 'align' => 'top' + ] + ), + new OOUI\FieldLayout( + new OOUI\TextInputWidget( [ + 'required' => true + ] ), + [ + 'label' => "TextInputWidget (required)\xE2\x80\x8E", + 'align' => 'top' + ] + ), + new OOUI\FieldLayout( + new OOUI\TextInputWidget( [ 'placeholder' => 'Placeholder' ] ), + [ + 'label' => "TextInputWidget (placeholder)\xE2\x80\x8E", + 'align' => 'top' + ] + ), + new OOUI\FieldLayout( + new OOUI\TextInputWidget( [ + 'value' => 'Title attribute', + 'title' => 'Title attribute with more information about me.' + ] ), + [ + 'label' => "TextInputWidget (with title)\xE2\x80\x8E", + 'align' => 'top' + ] + ), + new OOUI\FieldLayout( + new OOUI\TextInputWidget( [ 'type' => 'search' ] ), + [ + 'label' => "TextInputWidget (type=search)\xE2\x80\x8E", + 'align' => 'top' + ] + ), + new OOUI\FieldLayout( + new OOUI\TextInputWidget( [ + 'value' => 'Accesskey: S', + 'accessKey' => 's' + ] ), + [ + 'label' => "TextInputWidget (with accesskey)\xE2\x80\x8E", + 'align' => 'top', + 'help' => new OOUI\HtmlSnippet( 'Notice: Using `accesskey` might ' . + '<a href="http://webaim.org/techniques/keyboard/accesskey" target="_blank">' . + 'negatively impact screen readers</a>!' ) + ] + ), + new OOUI\FieldLayout( + new OOUI\TextInputWidget( [ + 'value' => 'Readonly', + 'readOnly' => true + ] ), + [ + 'label' => "TextInputWidget (readonly)\xE2\x80\x8E", + 'align' => 'top' + ] + ), + new OOUI\FieldLayout( + new OOUI\TextInputWidget( [ + 'value' => 'Disabled', + 'disabled' => true + ] ), + [ + 'label' => "TextInputWidget (disabled)\xE2\x80\x8E", + 'align' => 'top' + ] + ), + new OOUI\FieldLayout( + new OOUI\TextInputWidget( [ + 'multiline' => true, + 'value' => "Multiline\nMultiline" + ] ), + [ + 'label' => "TextInputWidget (multiline)\xE2\x80\x8E", + 'align' => 'top' + ] + ), + new OOUI\FieldLayout( + new OOUI\TextInputWidget( [ + 'multiline' => true, + 'rows' => 15, + 'value' => "Multiline\nMultiline" + ] ), + [ + 'label' => "TextInputWidget (multiline, rows=15)\xE2\x80\x8E", + 'align' => 'top' + ] + ), + new OOUI\FieldLayout( + new OOUI\TextInputWidget( [ + 'multiline' => true, + 'value' => "Multiline\nMultiline", + 'icon' => 'tag', + 'indicator' => 'required' + ] ), + [ + 'label' => "TextInputWidget (multiline, icon, indicator)\xE2\x80\x8E", + 'align' => 'top' + ] + ) + ] +] ) ); + +$demoContainer->appendContent( new OOUI\FieldsetLayout( [ + 'id' => 'demo-section-inputs-binary', + 'infusable' => true, + 'label' => 'Checkbox & Radio', 'items' => [ new OOUI\FieldLayout( new OOUI\CheckboxInputWidget( [ @@ -393,114 +590,15 @@ 'align' => 'top', 'label' => 'CheckboxMultiselectInputWidget', ] - ), - new OOUI\FieldLayout( - new OOUI\TextInputWidget( [ 'value' => 'Text input' ] ), - [ - 'label' => "TextInputWidget\xE2\x80\x8E", - 'align' => 'top' - ] - ), - new OOUI\FieldLayout( - new OOUI\TextInputWidget( [ 'icon' => 'help' ] ), - [ - 'label' => "TextInputWidget (icon)\xE2\x80\x8E", - 'align' => 'top' - ] - ), - new OOUI\FieldLayout( - new OOUI\TextInputWidget( [ - 'required' => true - ] ), - [ - 'label' => "TextInputWidget (required)\xE2\x80\x8E", - 'align' => 'top' - ] - ), - new OOUI\FieldLayout( - new OOUI\TextInputWidget( [ 'placeholder' => 'Placeholder' ] ), - [ - 'label' => "TextInputWidget (placeholder)\xE2\x80\x8E", - 'align' => 'top' - ] - ), - new OOUI\FieldLayout( - new OOUI\TextInputWidget( [ 'type' => 'search' ] ), - [ - 'label' => "TextInputWidget (type=search)\xE2\x80\x8E", - 'align' => 'top' - ] - ), - new OOUI\FieldLayout( - new OOUI\TextInputWidget( [ 'type' => 'number' ] ), - [ - 'label' => "TextInputWidget (type=number)\xE2\x80\x8E", - 'align' => 'top' - ] - ), - new OOUI\FieldLayout( - new OOUI\TextInputWidget( [ - 'value' => 'Readonly', - 'readOnly' => true - ] ), - [ - 'label' => "TextInputWidget (readonly)\xE2\x80\x8E", - 'align' => 'top' - ] - ), - new OOUI\FieldLayout( - new OOUI\TextInputWidget( [ - 'value' => 'Disabled', - 'disabled' => true - ] ), - [ - 'label' => "TextInputWidget (disabled)\xE2\x80\x8E", - 'align' => 'top' - ] - ), - new OOUI\FieldLayout( - new OOUI\TextInputWidget( [ - 'value' => 'Title attribute', - 'title' => 'Title attribute with more information about me.' - ] ), - [ - 'label' => "TextInputWidget (with title)\xE2\x80\x8E", - 'align' => 'top' - ] - ), - new OOUI\FieldLayout( - new OOUI\TextInputWidget( [ - 'multiline' => true, - 'value' => "Multiline\nMultiline" - ] ), - [ - 'label' => "TextInputWidget (multiline)\xE2\x80\x8E", - 'align' => 'top' - ] - ), - new OOUI\FieldLayout( - new OOUI\TextInputWidget( [ - 'multiline' => true, - 'rows' => 15, - 'value' => "Multiline\nMultiline" - ] ), - [ - 'label' => "TextInputWidget (multiline, rows=15)\xE2\x80\x8E", - 'align' => 'top' - ] - ), - new OOUI\FieldLayout( - new OOUI\TextInputWidget( [ - 'multiline' => true, - 'value' => "Multiline\nMultiline", - 'icon' => 'tag', - 'indicator' => 'required' - ] ), - [ - 'label' => "TextInputWidget (multiline, icon, indicator)\xE2\x80\x8E", - 'align' => 'top' - ] - ), + ) + ] +] ) ); + +$demoContainer->appendContent( new OOUI\FieldsetLayout( [ + 'id' => 'demo-section-dropdown', + 'infusable' => true, + 'label' => 'Dropdown', + 'items' => [ new OOUI\FieldLayout( new OOUI\DropdownInputWidget( [ 'options' => [ @@ -610,7 +708,15 @@ 'label' => "DropdownInputWidget (long)\xE2\x80\x8E", 'align' => 'top' ] - ), + ) + ] +] ) ); + +$demoContainer->appendContent( new OOUI\FieldsetLayout( [ + 'id' => 'demo-section-comboBox', + 'infusable' => true, + 'label' => 'ComboBox', + 'items' => [ new OOUI\FieldLayout( new OOUI\ComboBoxInputWidget( [ 'options' => [ @@ -648,124 +754,48 @@ 'label' => "ComboBoxInputWidget (empty)\xE2\x80\x8E", 'align' => 'top' ] - ), - new OOUI\FieldLayout( - new OOUI\ButtonInputWidget( [ - 'label' => 'Submit the form', - 'type' => 'submit', - 'flags' => [ 'primary', 'progressive' ], - 'useInputTag' => true - ] ), - [ - 'align' => 'top', - 'label' => "ButtonInputWidget (using <input>)\xE2\x80\x8E" - ] - ), - new OOUI\FieldLayout( - new OOUI\ButtonInputWidget( [ - 'label' => 'Another button', - 'type' => 'button' - ] ), - [ - 'align' => 'top', - 'label' => "ButtonInputWidget (using <button>)\xE2\x80\x8E" - ] - ), - new OOUI\FieldLayout( - new OOUI\ButtonInputWidget( [ - 'framed' => false, - 'label' => 'Another button', - 'type' => 'button' - ] ), - [ - 'align' => 'top', - 'label' => "ButtonInputWidget (frameless)\xE2\x80\x8E" - ] - ), - new OOUI\FieldLayout( - new OOUI\ButtonInputWidget( [ - 'framed' => false, - 'label' => 'Another button', - 'type' => 'button', - 'useInputTag' => true - ] ), - [ - 'align' => 'top', - 'label' => "ButtonInputWidget (frameless, using <input>)\xE2\x80\x8E" - ] - ), - new OOUI\FieldLayout( - new OOUI\ButtonWidget( [ - 'label' => 'Accesskey: H', - 'accessKey' => 'h' - ] ), - [ - 'label' => "ButtonWidget (with accesskey)\xE2\x80\x8E", - 'align' => 'top' - ] - ), - new OOUI\FieldLayout( - new OOUI\ButtonInputWidget( [ - 'label' => 'Accesskey: I', - 'accessKey' => 'i' - ] ), - [ - 'label' => "ButtonInputWidget (with accesskey)\xE2\x80\x8E", - 'align' => 'top' - ] - ), - new OOUI\FieldLayout( - new OOUI\TextInputWidget( [ - 'value' => 'Accesskey: S', - 'accessKey' => 's' - ] ), - [ - 'label' => "TextInputWidget (with accesskey)\xE2\x80\x8E", - 'align' => 'top' - ] ) ] ] ) ); -// We can't make the outer FieldsetLayout infusable, because the Widget in its FieldLayout -// is added with 'content', which is not preserved after infusion. But we need the Widget -// to wrap the HorizontalLayout. Need to think about this at some point. + $demoContainer->appendContent( new OOUI\FieldsetLayout( [ - 'infusable' => false, - 'label' => 'HorizontalLayout', + 'id' => 'demo-section-progressBar', + 'infusable' => true, + 'label' => 'Progress bar', 'items' => [ new OOUI\FieldLayout( - new OOUI\Widget( [ - 'content' => new OOUI\HorizontalLayout( [ - 'infusable' => true, - 'items' => [ - new OOUI\ButtonWidget( [ 'label' => 'Button' ] ), - new OOUI\ButtonGroupWidget( [ 'items' => [ - new OOUI\ButtonWidget( [ 'label' => 'A' ] ), - new OOUI\ButtonWidget( [ 'label' => 'B' ] ) - ] ] ), - new OOUI\ButtonInputWidget( [ 'label' => 'ButtonInput' ] ), - new OOUI\TextInputWidget( [ 'value' => 'TextInput' ] ), - new OOUI\DropdownInputWidget( [ 'options' => [ - [ - 'label' => 'DropdownInput', - 'data' => null - ] - ] ] ), - new OOUI\CheckboxInputWidget( [ 'selected' => true ] ), - new OOUI\RadioInputWidget( [ 'selected' => true ] ), - new OOUI\LabelWidget( [ 'label' => 'Label' ] ) - ], - ] ), + new OOUI\ProgressBarWidget( [ + 'progress' => 33 ] ), [ - 'label' => 'Multiple widgets shown as a single line, ' . - 'as used in compact forms or in parts of a bigger widget.', + 'label' => 'Progress bar', 'align' => 'top' ] ), - ], + new OOUI\FieldLayout( + new OOUI\ProgressBarWidget( [ + 'disabled' => true, + 'progress' => 50 + ] ), + [ + 'label' => 'Progress bar (disabled)', + 'align' => 'top' + ] + ), + new OOUI\FieldLayout( + new OOUI\ProgressBarWidget( [ + 'progress' => false + ] ), + [ + 'label' => 'Progress bar (indeterminate)', + 'align' => 'top' + ] + ), + ] ] ) ); + $demoContainer->appendContent( new OOUI\FieldsetLayout( [ + 'id' => 'demo-section-others', 'infusable' => true, 'label' => 'Other widgets', 'items' => [ @@ -852,7 +882,9 @@ ) ] ] ) ); + $demoContainer->appendContent( new OOUI\FieldsetLayout( [ + 'id' => 'demo-section-fieldLayouts', 'infusable' => true, 'label' => 'Field layouts', 'icon' => 'tag', @@ -1042,26 +1074,49 @@ 'errors' => [ 'The value must be a number.' ], 'align' => 'top' ] - ), - new OOUI\FieldLayout( - new OOUI\ProgressBarWidget( [ - 'progress' => 33 - ] ), - [ - 'label' => 'Progress bar', - 'align' => 'top' - ] - ), - new OOUI\FieldLayout( - new OOUI\ProgressBarWidget( [ - 'progress' => false - ] ), - [ - 'label' => 'Progress bar (indeterminate)', - 'align' => 'top' - ] - ), + ) ] +] ) ); + +// We can't make the outer FieldsetLayout infusable, because the Widget in its FieldLayout +// is added with 'content', which is not preserved after infusion. But we need the Widget +// to wrap the HorizontalLayout. Need to think about this at some point. +$demoContainer->appendContent( new OOUI\FieldsetLayout( [ + 'id' => 'demo-section-horizontalLayout', + 'infusable' => false, + 'label' => 'HorizontalLayout', + 'items' => [ + new OOUI\FieldLayout( + new OOUI\Widget( [ + 'content' => new OOUI\HorizontalLayout( [ + 'infusable' => true, + 'items' => [ + new OOUI\ButtonWidget( [ 'label' => 'Button' ] ), + new OOUI\ButtonGroupWidget( [ 'items' => [ + new OOUI\ButtonWidget( [ 'label' => 'A' ] ), + new OOUI\ButtonWidget( [ 'label' => 'B' ] ) + ] ] ), + new OOUI\ButtonInputWidget( [ 'label' => 'ButtonInput' ] ), + new OOUI\TextInputWidget( [ 'value' => 'TextInput' ] ), + new OOUI\DropdownInputWidget( [ 'options' => [ + [ + 'label' => 'DropdownInput', + 'data' => null + ] + ] ] ), + new OOUI\CheckboxInputWidget( [ 'selected' => true ] ), + new OOUI\RadioInputWidget( [ 'selected' => true ] ), + new OOUI\LabelWidget( [ 'label' => 'Label' ] ) + ], + ] ), + ] ), + [ + 'label' => 'Multiple widgets shown as a single line, ' . + 'as used in compact forms or in parts of a bigger widget.', + 'align' => 'top' + ] + ), + ], ] ) ); $demoContainer->appendContent( new OOUI\FormLayout( [ @@ -1070,6 +1125,7 @@ 'action' => 'demos.php', 'items' => [ new OOUI\FieldsetLayout( [ + 'id' => 'demo-section-formLayout', 'label' => 'Form layout', 'items' => [ new OOUI\FieldLayout( @@ -1101,6 +1157,18 @@ 'align' => 'inline', ] ), + new OOUI\FieldLayout( + new OOUI\HiddenInputWidget( [ + 'name' => 'hidden', + 'value' => 'hidden value', + ] ) + ), + new OOUI\FieldLayout( + new OOUI\ButtonInputWidget( [ + 'type' => 'submit', + 'label' => 'Submit form', + ] ) + ), ] ] ), new OOUI\FieldsetLayout( [ diff --git a/oojs/oojs-ui/demos/styles/demo.css b/oojs/oojs-ui/demos/styles/demo.css index 45c890f..73ae333 100644 --- a/oojs/oojs-ui/demos/styles/demo.css +++ b/oojs/oojs-ui/demos/styles/demo.css @@ -1,6 +1,7 @@ body { color: #222; - margin: 1em; + margin: 0 1em; + padding: 0; font-family: sans-serif; font-size: 0.8em; } @@ -16,18 +17,10 @@ } .demo-menu { - background-color: #fff; - position: fixed; - top: 0; - z-index: 1; - width: 62.5em; - padding-top: 1em; - /* To better hide Apex's large drop shadows */ - margin-left: -1em; - padding-left: 1em; - padding-right: 1em; - /* Support: Android < 5, iOS < 8 to tame their buggy behaviour */ - -webkit-backface-visibility: hidden; + min-width: 320px; /* Let's not pretend it works on anything lower than that */ + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; } .demo-menu > .oo-ui-widget { @@ -46,11 +39,6 @@ -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; -} - -/* This needs extra specificity to beat PanelLayout styles */ -.oo-ui-panelLayout.demo-container { - margin-top: 5em; } /* Console */ @@ -116,6 +104,7 @@ transform: rotate( -90deg ); } +.demo-console-collapsed .demo-sample-code, .demo-console-collapsed .demo-console-log, .demo-console-collapsed .demo-console-label, .demo-console-collapsed .demo-console-submit { @@ -218,6 +207,12 @@ color: #444; } +.demo-sample-code { + /* Need to override Prism (syntax highlighter) styles */ + background-color: #eaecf0; + margin: 0 !important; /* stylelint-disable-line declaration-no-important */ +} + /* Toolbars demo */ .demo-container.demo-toolbars { @@ -268,6 +263,12 @@ max-width: 10em; } +.demo-overlay { + position: absolute; + top: 0; + left: 0; +} + /* Special cases: ActionFieldLayout top aligned, FieldLayout left & right aligned */ .oo-ui-fieldLayout-align-left, @@ -294,8 +295,37 @@ padding: 1em 1em 1.5em 1em; } +/* + * Support: iOS 9.2, Android 4.4.4, Op Mobile 37, Chrome/Android 57, Fx/Android 52, UC Browser 11.4, Baidu 7.12 + * Workaround for weak ancient mobile browser support of `fixed` positioning + */ +@supports ( position: fixed ) { + .demo-menu { + background-color: #fff; + position: fixed; + top: 0; + border-bottom: 1px solid #a2a9b1; + padding-top: 1em; + box-shadow: 0 4px 4px -4px rgba( 0, 0, 0, 0.25 ); + z-index: 5; + } + + /* This needs extra specificity to beat PanelLayout styles */ + .demo-container.oo-ui-panelLayout { + /* Apex overrides. WikimediaUI wins for now in the demo framing in this browser subset */ + border-color: #a2a9b1; + border-radius: 2px; + box-shadow: none; + } + + .oo-ui-windowManager-modal > .oo-ui-dialog, + .oo-ui-processDialog-errors { + z-index: 6; + } +} + /* Media Queries */ -@media ( max-width: 750px ) { +@media ( min-width: 320px ) { body { font-size: 1em; } @@ -317,12 +347,74 @@ .demo-console-toggle { margin-right: -2em; } -} -@media ( min-width: 751px ) { - .demo-container { - padding: 2em; + @supports ( position: fixed ) { + .demo-menu { + min-height: 11.4em; + left: 1em; + right: 1em; + } + + /* Hide “Docs“ Button on very small screens */ + .demo-menu > .demo-button-docs { + display: none; + } + + /* This needs extra specificity to beat PanelLayout styles */ + .demo-container.oo-ui-panelLayout { + margin-top: 11.4em; + } } } +@media ( min-width: 568px ) { + @supports ( position: fixed ) { + .demo-menu { + min-height: 7.5em; + } + + .demo-menu > .demo-button-docs { + display: inline-block; + } + + .demo-container.oo-ui-panelLayout { + margin-top: 7.5em; + } + } +} + +@media ( min-width: 768px ) { + .demo-console-toggle { + margin-right: 0; + } +} + +@media ( min-width: 960px ) { + body { + font-size: 0.8em; + } + + .demo-container { + border-radius: 2px; + border-width: 1px; + padding: 2em; + } + + .demo-menu { + width: 62.5em; + white-space: nowrap; + } + + @supports ( position: fixed ) { + .demo-menu { + min-height: 4.5em; + left: auto; + right: auto; + } + + .demo-container.oo-ui-panelLayout { + margin-top: 4.5em; + } + } +} /* stylelint-enable selector-pseudo-element-colon-notation */ diff --git a/oojs/oojs-ui/i18n/id.json b/oojs/oojs-ui/i18n/id.json index ac7f6c6..c53e058 100644 --- a/oojs/oojs-ui/i18n/id.json +++ b/oojs/oojs-ui/i18n/id.json @@ -9,7 +9,8 @@ "McDutchie", "Rv77ax", "William Surya Permana", - "Rachmat.Wahidi" + "Rachmat.Wahidi", + "Rachmat04" ] }, "ooui-outline-control-move-down": "Pindahkan butir ke bawah", diff --git a/oojs/oojs-ui/package.json b/oojs/oojs-ui/package.json index 88a79a7..15eed0d 100644 --- a/oojs/oojs-ui/package.json +++ b/oojs/oojs-ui/package.json @@ -1,6 +1,6 @@ { "name": "oojs-ui", - "version": "0.21.4", + "version": "0.22.0", "description": "User interface classes built on the OOjs framework.", "keywords": [ "oojs-plugin", @@ -17,6 +17,7 @@ "predoc": "grunt build", "doc": "jsduck", "postdoc": "grunt copy:jsduck", + "quickdoc": "grunt quick-build && jsduck && grunt copy:jsduck", "publish-build": "grunt publish-build", "demos": "grunt publish-build && grunt demos", "jenkins": "npm test && jsduck && npm run postdoc" @@ -54,6 +55,7 @@ "karma-firefox-launcher": "1.0.0", "karma-qunit": "1.1.0", "karma-remap-istanbul": "0.6.0", + "prismjs": "1.6.0", "q": "1.4.1", "qunitjs": "1.22.0", "stylelint": "7.8.0", diff --git a/oojs/oojs-ui/php/themes/MediaWikiTheme.php b/oojs/oojs-ui/php/themes/MediaWikiTheme.php index c3a1745..1c37218 100644 --- a/oojs/oojs-ui/php/themes/MediaWikiTheme.php +++ b/oojs/oojs-ui/php/themes/MediaWikiTheme.php @@ -2,44 +2,5 @@ namespace OOUI; -class MediaWikiTheme extends Theme { - - /* Methods */ - - public function getElementClasses( Element $element ) { - $variants = [ - 'warning' => false, - 'invert' => false, - 'progressive' => false, - 'constructive' => false, - 'destructive' => false - ]; - - // Parent method - $classes = parent::getElementClasses( $element ); - - if ( $element->supports( [ 'hasFlag' ] ) ) { - $isFramed = $element->supports( [ 'isFramed' ] ) && $element->isFramed(); - $isActive = $element->supports( [ 'isActive' ] ) && $element->isActive(); - if ( $isFramed && ( $isActive || $element->isDisabled() || $element->hasFlag( 'primary' ) ) ) { - // Button with a dark background, use white icon - $variants['invert'] = true; - } elseif ( !$isFramed && $element->isDisabled() ) { - // Frameless disabled button, always use black icon regardless of flags - $variants['invert'] = false; - } elseif ( !$element->isDisabled() ) { - // Any other kind of button, use the right colored icon if available - $variants['progressive'] = $element->hasFlag( 'progressive' ); - $variants['constructive'] = $element->hasFlag( 'constructive' ); - $variants['destructive'] = $element->hasFlag( 'destructive' ); - $variants['warning'] = $element->hasFlag( 'warning' ); - } - } - - foreach ( $variants as $variant => $toggle ) { - $classes[$toggle ? 'on' : 'off'][] = 'oo-ui-image-' . $variant; - } - - return $classes; - } +class MediaWikiTheme extends WikimediaUITheme { } diff --git a/oojs/oojs-ui/php/themes/WikimediaUITheme.php b/oojs/oojs-ui/php/themes/WikimediaUITheme.php new file mode 100644 index 0000000..8c3f911 --- /dev/null +++ b/oojs/oojs-ui/php/themes/WikimediaUITheme.php @@ -0,0 +1,45 @@ +<?php + +namespace OOUI; + +class WikimediaUITheme extends Theme { + + /* Methods */ + + public function getElementClasses( Element $element ) { + $variants = [ + 'warning' => false, + 'invert' => false, + 'progressive' => false, + 'constructive' => false, + 'destructive' => false + ]; + + // Parent method + $classes = parent::getElementClasses( $element ); + + if ( $element->supports( [ 'hasFlag' ] ) ) { + $isFramed = $element->supports( [ 'isFramed' ] ) && $element->isFramed(); + $isActive = $element->supports( [ 'isActive' ] ) && $element->isActive(); + if ( $isFramed && ( $isActive || $element->isDisabled() || $element->hasFlag( 'primary' ) ) ) { + // Button with a dark background, use white icon + $variants['invert'] = true; + } elseif ( !$isFramed && $element->isDisabled() ) { + // Frameless disabled button, always use black icon regardless of flags + $variants['invert'] = false; + } elseif ( !$element->isDisabled() ) { + // Any other kind of button, use the right colored icon if available + $variants['progressive'] = $element->hasFlag( 'progressive' ); + $variants['constructive'] = $element->hasFlag( 'constructive' ); + $variants['destructive'] = $element->hasFlag( 'destructive' ); + $variants['warning'] = $element->hasFlag( 'warning' ); + } + } + + foreach ( $variants as $variant => $toggle ) { + $classes[$toggle ? 'on' : 'off'][] = 'oo-ui-image-' . $variant; + } + + return $classes; + } +} diff --git a/oojs/oojs-ui/php/widgets/CheckboxInputWidget.php b/oojs/oojs-ui/php/widgets/CheckboxInputWidget.php index 9e6e0d0..4b0beb9 100644 --- a/oojs/oojs-ui/php/widgets/CheckboxInputWidget.php +++ b/oojs/oojs-ui/php/widgets/CheckboxInputWidget.php @@ -31,7 +31,7 @@ // Initialization $this->addClasses( [ 'oo-ui-checkboxInputWidget' ] ); - // Required for pretty styling in MediaWiki theme + // Required for pretty styling in WikimediaUI theme $this->appendContent( new Tag( 'span' ) ); $this->setSelected( isset( $config['selected'] ) ? $config['selected'] : false ); } diff --git a/oojs/oojs-ui/php/widgets/HiddenInputWidget.php b/oojs/oojs-ui/php/widgets/HiddenInputWidget.php new file mode 100644 index 0000000..af1b234 --- /dev/null +++ b/oojs/oojs-ui/php/widgets/HiddenInputWidget.php @@ -0,0 +1,43 @@ +<?php + +namespace OOUI; + +/** + * Data widget intended for creating 'hidden'-type inputs. + */ +class HiddenInputWidget extends Widget { + + /** + * @var string + */ + public static $tagName = 'input'; + + /** + * DataWidget constructor. + * + * @param array $config + * @param string $config['value'] The data the input contains. (default: '') + * @param string $config['name'] The name of the hidden input. (default: '') + */ + public function __construct( array $config ) { + // Configuration initialization + $config = array_merge( [ 'value' => '', 'name' => '' ], $config ); + + // Parent constructor + parent::__construct( $config ); + + // Initialization + $this->setAttributes( [ + 'type' => 'hidden', + 'value' => $config['value'], + 'name' => $config['name'], + ] ); + $this->removeAttributes( [ 'aria-disabled' ] ); + } + + public function getConfig( &$config ) { + $config['value'] = $this->getAttribute( 'value' ); + $config['name'] = $this->getAttribute( 'name' ); + return parent::getConfig( $config ); + } +} diff --git a/oojs/oojs-ui/php/widgets/InputWidget.php b/oojs/oojs-ui/php/widgets/InputWidget.php index 8be7930..dfe918b 100644 --- a/oojs/oojs-ui/php/widgets/InputWidget.php +++ b/oojs/oojs-ui/php/widgets/InputWidget.php @@ -34,6 +34,7 @@ * @param string $config['name'] HTML input name (default: '') * @param string $config['value'] Input value (default: '') * @param string $config['dir'] The directionality of the input (ltr/rtl) + * @param string $config['inputId'] The value of the input’s HTML `id` attribute. */ public function __construct( array $config = [] ) { // Parent constructor @@ -65,6 +66,9 @@ $this->setValue( isset( $config['value'] ) ? $config['value'] : null ); if ( isset( $config['dir'] ) ) { $this->setDir( $config['dir'] ); + } + if ( isset( $config['inputId'] ) ) { + $this->setInputId( $config['inputId'] ); } } @@ -138,6 +142,17 @@ return $this; } + /** + * Set the 'id' attribute of the `<input>` element. + * + * @param string $id + * @return $this + */ + public function setInputId( $id ) { + $this->input->setAttributes( [ 'id' => $id ] ); + return $this; + } + public function getConfig( &$config ) { $name = $this->input->getAttribute( 'name' ); if ( $name !== null ) { @@ -146,6 +161,10 @@ if ( $this->value !== '' ) { $config['value'] = $this->value; } + $id = $this->input->getAttribute( 'id' ); + if ( $id !== null ) { + $config['inputId'] = $id; + } return parent::getConfig( $config ); } } diff --git a/oojs/oojs-ui/php/widgets/RadioInputWidget.php b/oojs/oojs-ui/php/widgets/RadioInputWidget.php index 4a0f359..72943d8 100644 --- a/oojs/oojs-ui/php/widgets/RadioInputWidget.php +++ b/oojs/oojs-ui/php/widgets/RadioInputWidget.php @@ -22,7 +22,7 @@ // Initialization $this->addClasses( [ 'oo-ui-radioInputWidget' ] ); - // Required for pretty styling in MediaWiki theme + // Required for pretty styling in WikimediaUI theme $this->appendContent( new Tag( 'span' ) ); $this->setSelected( isset( $config['selected'] ) ? $config['selected'] : false ); } diff --git a/oojs/oojs-ui/php/widgets/TextInputWidget.php b/oojs/oojs-ui/php/widgets/TextInputWidget.php index 20cf035..885c155 100644 --- a/oojs/oojs-ui/php/widgets/TextInputWidget.php +++ b/oojs/oojs-ui/php/widgets/TextInputWidget.php @@ -186,7 +186,6 @@ $allowedTypes = [ 'text', 'password', - 'search', 'email', 'url', 'number' -- To view, visit https://gerrit.wikimedia.org/r/356313 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I93b66d5339e6766f46dfcc5b22abaeadd74d8da0 Gerrit-PatchSet: 1 Gerrit-Project: mediawiki/vendor Gerrit-Branch: master Gerrit-Owner: Jforrester <[email protected]> _______________________________________________ MediaWiki-commits mailing list [email protected] https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits
