Merge "mediawiki.jqueryMsg: Deprecate window.gM"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Fri, 14 Feb 2014 01:08:45 +0000 (01:08 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Fri, 14 Feb 2014 01:08:45 +0000 (01:08 +0000)
415 files changed:
.jshintignore
RELEASE-NOTES-1.23
includes/DefaultSettings.php
includes/Title.php
includes/WikiPage.php
includes/externalstore/ExternalStoreMwstore.php
includes/specials/SpecialProtectedpages.php
languages/messages/MessagesAst.php
languages/messages/MessagesBe_tarask.php
languages/messages/MessagesDe.php
languages/messages/MessagesEn.php
languages/messages/MessagesEo.php
languages/messages/MessagesFi.php
languages/messages/MessagesFr.php
languages/messages/MessagesHi.php
languages/messages/MessagesKm.php
languages/messages/MessagesKo.php
languages/messages/MessagesKsh.php
languages/messages/MessagesMk.php
languages/messages/MessagesPl.php
languages/messages/MessagesPt.php
languages/messages/MessagesPt_br.php
languages/messages/MessagesQqq.php
languages/messages/MessagesRo.php
languages/messages/MessagesSh.php
languages/messages/MessagesSl.php
languages/messages/MessagesWar.php
maintenance/jsduck/categories.json
maintenance/jsduck/config.json
maintenance/language/messageTypes.inc
maintenance/language/messages.inc
resources/Resources.php
resources/jquery/jquery.ba-throttle-debounce.js [new file with mode: 0644]
resources/mediawiki.api/mediawiki.api.js
resources/mediawiki.special/mediawiki.special.css
resources/mediawiki/mediawiki.feedback.js
resources/mediawiki/mediawiki.jqueryMsg.js
resources/mediawiki/mediawiki.jqueryMsg.peg
resources/oojs-ui/i18n/ace.json [new file with mode: 0644]
resources/oojs-ui/i18n/af.json [new file with mode: 0644]
resources/oojs-ui/i18n/am.json [new file with mode: 0644]
resources/oojs-ui/i18n/ar.json [new file with mode: 0644]
resources/oojs-ui/i18n/arc.json [new file with mode: 0644]
resources/oojs-ui/i18n/ast.json [new file with mode: 0644]
resources/oojs-ui/i18n/az.json [new file with mode: 0644]
resources/oojs-ui/i18n/ba.json [new file with mode: 0644]
resources/oojs-ui/i18n/bcl.json [new file with mode: 0644]
resources/oojs-ui/i18n/be-tarask.json [new file with mode: 0644]
resources/oojs-ui/i18n/be.json [new file with mode: 0644]
resources/oojs-ui/i18n/bg.json [new file with mode: 0644]
resources/oojs-ui/i18n/bn.json [new file with mode: 0644]
resources/oojs-ui/i18n/br.json [new file with mode: 0644]
resources/oojs-ui/i18n/bs.json [new file with mode: 0644]
resources/oojs-ui/i18n/ca.json [new file with mode: 0644]
resources/oojs-ui/i18n/ce.json [new file with mode: 0644]
resources/oojs-ui/i18n/ckb.json [new file with mode: 0644]
resources/oojs-ui/i18n/co.json [new file with mode: 0644]
resources/oojs-ui/i18n/cs.json [new file with mode: 0644]
resources/oojs-ui/i18n/cu.json [new file with mode: 0644]
resources/oojs-ui/i18n/cy.json [new file with mode: 0644]
resources/oojs-ui/i18n/da.json [new file with mode: 0644]
resources/oojs-ui/i18n/de.json [new file with mode: 0644]
resources/oojs-ui/i18n/diq.json [new file with mode: 0644]
resources/oojs-ui/i18n/dsb.json [new file with mode: 0644]
resources/oojs-ui/i18n/el.json [new file with mode: 0644]
resources/oojs-ui/i18n/eml.json [new file with mode: 0644]
resources/oojs-ui/i18n/en.json [new file with mode: 0644]
resources/oojs-ui/i18n/eo.json [new file with mode: 0644]
resources/oojs-ui/i18n/es.json [new file with mode: 0644]
resources/oojs-ui/i18n/et.json [new file with mode: 0644]
resources/oojs-ui/i18n/eu.json [new file with mode: 0644]
resources/oojs-ui/i18n/fa.json [new file with mode: 0644]
resources/oojs-ui/i18n/fi.json [new file with mode: 0644]
resources/oojs-ui/i18n/fo.json [new file with mode: 0644]
resources/oojs-ui/i18n/fr.json [new file with mode: 0644]
resources/oojs-ui/i18n/frr.json [new file with mode: 0644]
resources/oojs-ui/i18n/fur.json [new file with mode: 0644]
resources/oojs-ui/i18n/gl.json [new file with mode: 0644]
resources/oojs-ui/i18n/gu.json [new file with mode: 0644]
resources/oojs-ui/i18n/he.json [new file with mode: 0644]
resources/oojs-ui/i18n/hi.json [new file with mode: 0644]
resources/oojs-ui/i18n/hr.json [new file with mode: 0644]
resources/oojs-ui/i18n/hsb.json [new file with mode: 0644]
resources/oojs-ui/i18n/hu.json [new file with mode: 0644]
resources/oojs-ui/i18n/hy.json [new file with mode: 0644]
resources/oojs-ui/i18n/ia.json [new file with mode: 0644]
resources/oojs-ui/i18n/id.json [new file with mode: 0644]
resources/oojs-ui/i18n/ie.json [new file with mode: 0644]
resources/oojs-ui/i18n/ilo.json [new file with mode: 0644]
resources/oojs-ui/i18n/is.json [new file with mode: 0644]
resources/oojs-ui/i18n/it.json [new file with mode: 0644]
resources/oojs-ui/i18n/ja.json [new file with mode: 0644]
resources/oojs-ui/i18n/jv.json [new file with mode: 0644]
resources/oojs-ui/i18n/ka.json [new file with mode: 0644]
resources/oojs-ui/i18n/kk-cyrl.json [new file with mode: 0644]
resources/oojs-ui/i18n/km.json [new file with mode: 0644]
resources/oojs-ui/i18n/ko.json [new file with mode: 0644]
resources/oojs-ui/i18n/krc.json [new file with mode: 0644]
resources/oojs-ui/i18n/kw.json [new file with mode: 0644]
resources/oojs-ui/i18n/ky.json [new file with mode: 0644]
resources/oojs-ui/i18n/lb.json [new file with mode: 0644]
resources/oojs-ui/i18n/lmo.json [new file with mode: 0644]
resources/oojs-ui/i18n/lt.json [new file with mode: 0644]
resources/oojs-ui/i18n/lv.json [new file with mode: 0644]
resources/oojs-ui/i18n/mg.json [new file with mode: 0644]
resources/oojs-ui/i18n/min.json [new file with mode: 0644]
resources/oojs-ui/i18n/mk.json [new file with mode: 0644]
resources/oojs-ui/i18n/ml.json [new file with mode: 0644]
resources/oojs-ui/i18n/mr.json [new file with mode: 0644]
resources/oojs-ui/i18n/ms.json [new file with mode: 0644]
resources/oojs-ui/i18n/nap.json [new file with mode: 0644]
resources/oojs-ui/i18n/nb.json [new file with mode: 0644]
resources/oojs-ui/i18n/nds-nl.json [new file with mode: 0644]
resources/oojs-ui/i18n/nds.json [new file with mode: 0644]
resources/oojs-ui/i18n/ne.json [new file with mode: 0644]
resources/oojs-ui/i18n/nl.json [new file with mode: 0644]
resources/oojs-ui/i18n/nn.json [new file with mode: 0644]
resources/oojs-ui/i18n/om.json [new file with mode: 0644]
resources/oojs-ui/i18n/or.json [new file with mode: 0644]
resources/oojs-ui/i18n/pa.json [new file with mode: 0644]
resources/oojs-ui/i18n/pl.json [new file with mode: 0644]
resources/oojs-ui/i18n/pms.json [new file with mode: 0644]
resources/oojs-ui/i18n/ps.json [new file with mode: 0644]
resources/oojs-ui/i18n/pt-br.json [new file with mode: 0644]
resources/oojs-ui/i18n/pt.json [new file with mode: 0644]
resources/oojs-ui/i18n/qqq.json [new file with mode: 0644]
resources/oojs-ui/i18n/qu.json [new file with mode: 0644]
resources/oojs-ui/i18n/ro.json [new file with mode: 0644]
resources/oojs-ui/i18n/roa-tara.json [new file with mode: 0644]
resources/oojs-ui/i18n/ru.json [new file with mode: 0644]
resources/oojs-ui/i18n/sah.json [new file with mode: 0644]
resources/oojs-ui/i18n/scn.json [new file with mode: 0644]
resources/oojs-ui/i18n/sh.json [new file with mode: 0644]
resources/oojs-ui/i18n/si.json [new file with mode: 0644]
resources/oojs-ui/i18n/sk.json [new file with mode: 0644]
resources/oojs-ui/i18n/sl.json [new file with mode: 0644]
resources/oojs-ui/i18n/sq.json [new file with mode: 0644]
resources/oojs-ui/i18n/sr-ec.json [new file with mode: 0644]
resources/oojs-ui/i18n/sv.json [new file with mode: 0644]
resources/oojs-ui/i18n/sw.json [new file with mode: 0644]
resources/oojs-ui/i18n/ta.json [new file with mode: 0644]
resources/oojs-ui/i18n/te.json [new file with mode: 0644]
resources/oojs-ui/i18n/th.json [new file with mode: 0644]
resources/oojs-ui/i18n/tl.json [new file with mode: 0644]
resources/oojs-ui/i18n/tr.json [new file with mode: 0644]
resources/oojs-ui/i18n/tt-cyrl.json [new file with mode: 0644]
resources/oojs-ui/i18n/ug-arab.json [new file with mode: 0644]
resources/oojs-ui/i18n/uk.json [new file with mode: 0644]
resources/oojs-ui/i18n/uz.json [new file with mode: 0644]
resources/oojs-ui/i18n/vec.json [new file with mode: 0644]
resources/oojs-ui/i18n/vi.json [new file with mode: 0644]
resources/oojs-ui/i18n/vo.json [new file with mode: 0644]
resources/oojs-ui/i18n/wuu.json [new file with mode: 0644]
resources/oojs-ui/i18n/yi.json [new file with mode: 0644]
resources/oojs-ui/i18n/yo.json [new file with mode: 0644]
resources/oojs-ui/i18n/zh-hans.json [new file with mode: 0644]
resources/oojs-ui/i18n/zh-hant.json [new file with mode: 0644]
resources/oojs-ui/i18n/zh-hk.json [new file with mode: 0644]
resources/oojs-ui/i18n/zh-tw.json [new file with mode: 0644]
resources/oojs-ui/images/fade-down.png [new file with mode: 0644]
resources/oojs-ui/images/fade-up.png [new file with mode: 0644]
resources/oojs-ui/images/icons/accept.png [new file with mode: 0644]
resources/oojs-ui/images/icons/accept.svg [new file with mode: 0644]
resources/oojs-ui/images/icons/add-item.png [new file with mode: 0644]
resources/oojs-ui/images/icons/add-item.svg [new file with mode: 0644]
resources/oojs-ui/images/icons/advanced.png [new file with mode: 0644]
resources/oojs-ui/images/icons/advanced.svg [new file with mode: 0644]
resources/oojs-ui/images/icons/alert.png [new file with mode: 0644]
resources/oojs-ui/images/icons/alert.svg [new file with mode: 0644]
resources/oojs-ui/images/icons/arched-arrow-ltr.png [new file with mode: 0644]
resources/oojs-ui/images/icons/arched-arrow-ltr.svg [new file with mode: 0644]
resources/oojs-ui/images/icons/arched-arrow-rtl.png [new file with mode: 0644]
resources/oojs-ui/images/icons/arched-arrow-rtl.svg [new file with mode: 0644]
resources/oojs-ui/images/icons/check.png [new file with mode: 0644]
resources/oojs-ui/images/icons/check.svg [new file with mode: 0644]
resources/oojs-ui/images/icons/clear.png [new file with mode: 0644]
resources/oojs-ui/images/icons/clear.svg [new file with mode: 0644]
resources/oojs-ui/images/icons/close.png [new file with mode: 0644]
resources/oojs-ui/images/icons/close.svg [new file with mode: 0644]
resources/oojs-ui/images/icons/code.png [new file with mode: 0644]
resources/oojs-ui/images/icons/code.svg [new file with mode: 0644]
resources/oojs-ui/images/icons/collapse.png [new file with mode: 0644]
resources/oojs-ui/images/icons/collapse.svg [new file with mode: 0644]
resources/oojs-ui/images/icons/comment.png [new file with mode: 0644]
resources/oojs-ui/images/icons/comment.svg [new file with mode: 0644]
resources/oojs-ui/images/icons/expand.png [new file with mode: 0644]
resources/oojs-ui/images/icons/expand.svg [new file with mode: 0644]
resources/oojs-ui/images/icons/help.png [new file with mode: 0644]
resources/oojs-ui/images/icons/help.svg [new file with mode: 0644]
resources/oojs-ui/images/icons/history.png [new file with mode: 0644]
resources/oojs-ui/images/icons/history.svg [new file with mode: 0644]
resources/oojs-ui/images/icons/link.png [new file with mode: 0644]
resources/oojs-ui/images/icons/link.svg [new file with mode: 0644]
resources/oojs-ui/images/icons/menu.png [new file with mode: 0644]
resources/oojs-ui/images/icons/menu.svg [new file with mode: 0644]
resources/oojs-ui/images/icons/move-ltr.png [new file with mode: 0644]
resources/oojs-ui/images/icons/move-ltr.svg [new file with mode: 0644]
resources/oojs-ui/images/icons/move-rtl.png [new file with mode: 0644]
resources/oojs-ui/images/icons/move-rtl.svg [new file with mode: 0644]
resources/oojs-ui/images/icons/picture.png [new file with mode: 0644]
resources/oojs-ui/images/icons/picture.svg [new file with mode: 0644]
resources/oojs-ui/images/icons/remove-item.png [new file with mode: 0644]
resources/oojs-ui/images/icons/remove-item.svg [new file with mode: 0644]
resources/oojs-ui/images/icons/remove.png [new file with mode: 0644]
resources/oojs-ui/images/icons/remove.svg [new file with mode: 0644]
resources/oojs-ui/images/icons/search.png [new file with mode: 0644]
resources/oojs-ui/images/icons/search.svg [new file with mode: 0644]
resources/oojs-ui/images/icons/settings.png [new file with mode: 0644]
resources/oojs-ui/images/icons/settings.svg [new file with mode: 0644]
resources/oojs-ui/images/icons/tag.png [new file with mode: 0644]
resources/oojs-ui/images/icons/tag.svg [new file with mode: 0644]
resources/oojs-ui/images/icons/window.png [new file with mode: 0644]
resources/oojs-ui/images/icons/window.svg [new file with mode: 0644]
resources/oojs-ui/images/indicators/down.png [new file with mode: 0644]
resources/oojs-ui/images/indicators/down.svg [new file with mode: 0644]
resources/oojs-ui/images/indicators/required.png [new file with mode: 0644]
resources/oojs-ui/images/indicators/required.svg [new file with mode: 0644]
resources/oojs-ui/images/indicators/up.png [new file with mode: 0644]
resources/oojs-ui/images/indicators/up.svg [new file with mode: 0644]
resources/oojs-ui/images/tail.svg [new file with mode: 0644]
resources/oojs-ui/images/textures/pending.gif [new file with mode: 0644]
resources/oojs-ui/images/textures/transparency.png [new file with mode: 0644]
resources/oojs-ui/images/toolbar-shadow.png [new file with mode: 0644]
resources/oojs-ui/oojs-ui.js [new file with mode: 0644]
resources/oojs-ui/oojs-ui.svg.css [new file with mode: 0644]
resources/oojs/.gitignore [deleted file]
resources/oojs/i18n/ace.json [deleted file]
resources/oojs/i18n/af.json [deleted file]
resources/oojs/i18n/am.json [deleted file]
resources/oojs/i18n/ar.json [deleted file]
resources/oojs/i18n/arc.json [deleted file]
resources/oojs/i18n/ast.json [deleted file]
resources/oojs/i18n/az.json [deleted file]
resources/oojs/i18n/ba.json [deleted file]
resources/oojs/i18n/bcl.json [deleted file]
resources/oojs/i18n/be-tarask.json [deleted file]
resources/oojs/i18n/be.json [deleted file]
resources/oojs/i18n/bg.json [deleted file]
resources/oojs/i18n/bn.json [deleted file]
resources/oojs/i18n/br.json [deleted file]
resources/oojs/i18n/bs.json [deleted file]
resources/oojs/i18n/ca.json [deleted file]
resources/oojs/i18n/ce.json [deleted file]
resources/oojs/i18n/ckb.json [deleted file]
resources/oojs/i18n/co.json [deleted file]
resources/oojs/i18n/cs.json [deleted file]
resources/oojs/i18n/cu.json [deleted file]
resources/oojs/i18n/cy.json [deleted file]
resources/oojs/i18n/da.json [deleted file]
resources/oojs/i18n/de.json [deleted file]
resources/oojs/i18n/diq.json [deleted file]
resources/oojs/i18n/dsb.json [deleted file]
resources/oojs/i18n/el.json [deleted file]
resources/oojs/i18n/eml.json [deleted file]
resources/oojs/i18n/en.json [deleted file]
resources/oojs/i18n/eo.json [deleted file]
resources/oojs/i18n/es.json [deleted file]
resources/oojs/i18n/et.json [deleted file]
resources/oojs/i18n/eu.json [deleted file]
resources/oojs/i18n/fa.json [deleted file]
resources/oojs/i18n/fi.json [deleted file]
resources/oojs/i18n/fo.json [deleted file]
resources/oojs/i18n/fr.json [deleted file]
resources/oojs/i18n/frr.json [deleted file]
resources/oojs/i18n/fur.json [deleted file]
resources/oojs/i18n/gl.json [deleted file]
resources/oojs/i18n/gu.json [deleted file]
resources/oojs/i18n/he.json [deleted file]
resources/oojs/i18n/hi.json [deleted file]
resources/oojs/i18n/hr.json [deleted file]
resources/oojs/i18n/hsb.json [deleted file]
resources/oojs/i18n/hu.json [deleted file]
resources/oojs/i18n/hy.json [deleted file]
resources/oojs/i18n/ia.json [deleted file]
resources/oojs/i18n/id.json [deleted file]
resources/oojs/i18n/ie.json [deleted file]
resources/oojs/i18n/ilo.json [deleted file]
resources/oojs/i18n/is.json [deleted file]
resources/oojs/i18n/it.json [deleted file]
resources/oojs/i18n/ja.json [deleted file]
resources/oojs/i18n/jv.json [deleted file]
resources/oojs/i18n/ka.json [deleted file]
resources/oojs/i18n/kk-cyrl.json [deleted file]
resources/oojs/i18n/ko.json [deleted file]
resources/oojs/i18n/krc.json [deleted file]
resources/oojs/i18n/kw.json [deleted file]
resources/oojs/i18n/ky.json [deleted file]
resources/oojs/i18n/lb.json [deleted file]
resources/oojs/i18n/lmo.json [deleted file]
resources/oojs/i18n/lt.json [deleted file]
resources/oojs/i18n/lv.json [deleted file]
resources/oojs/i18n/mg.json [deleted file]
resources/oojs/i18n/min.json [deleted file]
resources/oojs/i18n/mk.json [deleted file]
resources/oojs/i18n/ml.json [deleted file]
resources/oojs/i18n/mr.json [deleted file]
resources/oojs/i18n/ms.json [deleted file]
resources/oojs/i18n/nap.json [deleted file]
resources/oojs/i18n/nb.json [deleted file]
resources/oojs/i18n/nds-nl.json [deleted file]
resources/oojs/i18n/nds.json [deleted file]
resources/oojs/i18n/ne.json [deleted file]
resources/oojs/i18n/nl.json [deleted file]
resources/oojs/i18n/nn.json [deleted file]
resources/oojs/i18n/om.json [deleted file]
resources/oojs/i18n/or.json [deleted file]
resources/oojs/i18n/pa.json [deleted file]
resources/oojs/i18n/pl.json [deleted file]
resources/oojs/i18n/pms.json [deleted file]
resources/oojs/i18n/ps.json [deleted file]
resources/oojs/i18n/pt-br.json [deleted file]
resources/oojs/i18n/pt.json [deleted file]
resources/oojs/i18n/qqq.json [deleted file]
resources/oojs/i18n/qu.json [deleted file]
resources/oojs/i18n/ro.json [deleted file]
resources/oojs/i18n/roa-tara.json [deleted file]
resources/oojs/i18n/ru.json [deleted file]
resources/oojs/i18n/sah.json [deleted file]
resources/oojs/i18n/scn.json [deleted file]
resources/oojs/i18n/sh.json [deleted file]
resources/oojs/i18n/si.json [deleted file]
resources/oojs/i18n/sk.json [deleted file]
resources/oojs/i18n/sl.json [deleted file]
resources/oojs/i18n/sq.json [deleted file]
resources/oojs/i18n/sr-ec.json [deleted file]
resources/oojs/i18n/sv.json [deleted file]
resources/oojs/i18n/sw.json [deleted file]
resources/oojs/i18n/ta.json [deleted file]
resources/oojs/i18n/te.json [deleted file]
resources/oojs/i18n/th.json [deleted file]
resources/oojs/i18n/tl.json [deleted file]
resources/oojs/i18n/tr.json [deleted file]
resources/oojs/i18n/tt-cyrl.json [deleted file]
resources/oojs/i18n/ug-arab.json [deleted file]
resources/oojs/i18n/uk.json [deleted file]
resources/oojs/i18n/uz.json [deleted file]
resources/oojs/i18n/vec.json [deleted file]
resources/oojs/i18n/vi.json [deleted file]
resources/oojs/i18n/vo.json [deleted file]
resources/oojs/i18n/wuu.json [deleted file]
resources/oojs/i18n/yi.json [deleted file]
resources/oojs/i18n/yo.json [deleted file]
resources/oojs/i18n/zh-hans.json [deleted file]
resources/oojs/i18n/zh-hant.json [deleted file]
resources/oojs/i18n/zh-hk.json [deleted file]
resources/oojs/i18n/zh-tw.json [deleted file]
resources/oojs/images/fade-down.png [deleted file]
resources/oojs/images/fade-up.png [deleted file]
resources/oojs/images/icons/accept.png [deleted file]
resources/oojs/images/icons/accept.svg [deleted file]
resources/oojs/images/icons/add-item.png [deleted file]
resources/oojs/images/icons/add-item.svg [deleted file]
resources/oojs/images/icons/advanced.png [deleted file]
resources/oojs/images/icons/advanced.svg [deleted file]
resources/oojs/images/icons/alert.png [deleted file]
resources/oojs/images/icons/alert.svg [deleted file]
resources/oojs/images/icons/arched-arrow-ltr.png [deleted file]
resources/oojs/images/icons/arched-arrow-ltr.svg [deleted file]
resources/oojs/images/icons/arched-arrow-rtl.png [deleted file]
resources/oojs/images/icons/arched-arrow-rtl.svg [deleted file]
resources/oojs/images/icons/check.png [deleted file]
resources/oojs/images/icons/check.svg [deleted file]
resources/oojs/images/icons/clear.png [deleted file]
resources/oojs/images/icons/clear.svg [deleted file]
resources/oojs/images/icons/close.png [deleted file]
resources/oojs/images/icons/close.svg [deleted file]
resources/oojs/images/icons/code.png [deleted file]
resources/oojs/images/icons/code.svg [deleted file]
resources/oojs/images/icons/collapse.png [deleted file]
resources/oojs/images/icons/collapse.svg [deleted file]
resources/oojs/images/icons/comment.png [deleted file]
resources/oojs/images/icons/comment.svg [deleted file]
resources/oojs/images/icons/expand.png [deleted file]
resources/oojs/images/icons/expand.svg [deleted file]
resources/oojs/images/icons/help.png [deleted file]
resources/oojs/images/icons/help.svg [deleted file]
resources/oojs/images/icons/history.png [deleted file]
resources/oojs/images/icons/history.svg [deleted file]
resources/oojs/images/icons/link.png [deleted file]
resources/oojs/images/icons/link.svg [deleted file]
resources/oojs/images/icons/menu.png [deleted file]
resources/oojs/images/icons/menu.svg [deleted file]
resources/oojs/images/icons/move-ltr.png [deleted file]
resources/oojs/images/icons/move-ltr.svg [deleted file]
resources/oojs/images/icons/move-rtl.png [deleted file]
resources/oojs/images/icons/move-rtl.svg [deleted file]
resources/oojs/images/icons/picture.png [deleted file]
resources/oojs/images/icons/picture.svg [deleted file]
resources/oojs/images/icons/remove-item.png [deleted file]
resources/oojs/images/icons/remove-item.svg [deleted file]
resources/oojs/images/icons/remove.png [deleted file]
resources/oojs/images/icons/remove.svg [deleted file]
resources/oojs/images/icons/search.png [deleted file]
resources/oojs/images/icons/search.svg [deleted file]
resources/oojs/images/icons/settings.png [deleted file]
resources/oojs/images/icons/settings.svg [deleted file]
resources/oojs/images/icons/tag.png [deleted file]
resources/oojs/images/icons/tag.svg [deleted file]
resources/oojs/images/icons/window.png [deleted file]
resources/oojs/images/icons/window.svg [deleted file]
resources/oojs/images/indicators/down.png [deleted file]
resources/oojs/images/indicators/down.svg [deleted file]
resources/oojs/images/indicators/required.png [deleted file]
resources/oojs/images/indicators/required.svg [deleted file]
resources/oojs/images/indicators/up.png [deleted file]
resources/oojs/images/indicators/up.svg [deleted file]
resources/oojs/images/tail.svg [deleted file]
resources/oojs/images/textures/pending.gif [deleted file]
resources/oojs/images/textures/transparency.png [deleted file]
resources/oojs/images/toolbar-shadow.png [deleted file]
resources/oojs/oojs-ui.js [deleted file]
resources/oojs/oojs-ui.svg.css [deleted file]
skins/vector/components/tabs.less
skins/vector/variables.less
tests/qunit/suites/resources/mediawiki/mediawiki.jqueryMsg.test.js

index b161f1f..73b0860 100644 (file)
@@ -11,6 +11,7 @@ extensions/
 node_modules/
 resources/jquery/jquery.appear.js
 resources/jquery/jquery.async.js
+resources/jquery/jquery.ba-throttle-debounce.js
 resources/jquery/jquery.cookie.js
 resources/jquery/jquery.cycle.all.js
 resources/jquery/jquery.farbtastic.js
@@ -29,6 +30,7 @@ resources/jquery.tipsy/
 resources/jquery.ui/
 resources/mediawiki.libs/
 resources/oojs/
+resources/oojs-ui/
 resources/sinonjs/
 
 # github.com/jshint/jshint/issues/729
index 16bdf1e..ccde5cc 100644 (file)
@@ -34,6 +34,8 @@ production.
 * The 'max threads' setting was removed from $wgDBservers.
 * Support for AdminSettings.php has been completely removed. All configuration
   belongs in LocalSettings.php.
+* Special:ProtectedPages shows now a table. The timestamp, the reason and
+  the protecting user is also shown.
 
 === New features in 1.23 ===
 * ResourceLoader can utilize the Web Storage API to cache modules client-side.
@@ -88,6 +90,8 @@ production.
   links.
 * Added MessageCache::get hook as a new way to customize messages across
   multiple sites.
+* Added jquery.throttle-debounce ResourceLoader module to limit the number of
+  callbacks for frequently occurring events.
 
 === Bug fixes in 1.23 ===
 * (bug 41759) The "updated since last visit" markers (on history pages, recent
index bb80beb..dd76a04 100644 (file)
@@ -5958,21 +5958,21 @@ $wgExtensionMessagesFiles = array();
  *
  * @par Simple example:
  * @code
- *    $wgMessagesDirs['ConfirmEdit'] = __DIR__ . '/i18n';
+ *    $wgMessagesDirs['Example'] = __DIR__ . '/i18n';
  * @endcode
  *
  * @par Complex example:
  * @code
- *    $wgMessagesDirs['VisualEditor'] = array(
- *        __DIR__ . '/lib/ve/modules/ve/i18n',
- *        __DIR__ . '/modules/ve-mw/i18n',
- *        __DIR__ . '/modules/ve-wmf/i18n',
+ *    $wgMessagesDirs['Example'] = array(
+ *        __DIR__ . '/lib/ve/i18n',
+ *        __DIR__ . '/lib/oojs-ui/i18n',
+ *        __DIR__ . '/i18n',
  *    )
  * @endcode
  * @since 1.23
  */
 $wgMessagesDirs = array(
-       "$IP/resources/oojs/i18n",
+       "$IP/resources/oojs-ui/i18n",
 );
 
 /**
index dc9822a..ab79d6d 100644 (file)
@@ -3876,7 +3876,20 @@ class Title {
                                $comment .= wfMessage( 'colon-separator' )->inContentLanguage()->text() . $reason;
                        }
                        // @todo FIXME: $params?
-                       $log->addEntry( 'move_prot', $nt, $comment, array( $this->getPrefixedText() ), $wgUser );
+                       $logId = $log->addEntry( 'move_prot', $nt, $comment, array( $this->getPrefixedText() ), $wgUser );
+
+                       // reread inserted pr_ids for log relation
+                       $insertedPrIds = $dbw->select(
+                               'page_restrictions',
+                               'pr_id',
+                               array( 'pr_page' => $redirid ),
+                               __METHOD__
+                       );
+                       $logRelationsValues = array();
+                       foreach ( $insertedPrIds as $prid ) {
+                               $logRelationsValues[] = $prid->pr_id;
+                       }
+                       $log->addRelations( 'pr_id', $logRelationsValues, $logId );
                }
 
                # Update watchlists
index ee6f574..bcd0f69 100644 (file)
@@ -144,7 +144,7 @@ class WikiPage implements Page, IDBAccessObject {
        public static function newFromID( $id, $from = 'fromdb' ) {
                // page id's are never 0 or negative, see bug 61166
                if ( $id < 1 ) {
-                       return;
+                       return null;
                }
 
                $from = self::convertSelectType( $from );
@@ -2355,6 +2355,9 @@ class WikiPage implements Page, IDBAccessObject {
                // Truncate for whole multibyte characters
                $reason = $wgContLang->truncate( $reason, 255 );
 
+               $logRelationsValues = array();
+               $logRelationsField = null;
+
                if ( $id ) { // Protection of existing page
                        if ( !wfRunHooks( 'ArticleProtect', array( &$this, &$user, $limit, $reason ) ) ) {
                                return Status::newGood();
@@ -2389,11 +2392,24 @@ class WikiPage implements Page, IDBAccessObject {
                                return Status::newFatal( 'no-null-revision', $this->mTitle->getPrefixedText() );
                        }
 
+                       $logRelationsField = 'pr_id';
+
                        // Update restrictions table
                        foreach ( $limit as $action => $restrictions ) {
+                               $dbw->delete(
+                                       'page_restrictions',
+                                       array(
+                                               'pr_page' => $id,
+                                               'pr_type' => $action
+                                       ),
+                                       __METHOD__
+                               );
                                if ( $restrictions != '' ) {
-                                       $dbw->replace( 'page_restrictions', array( array( 'pr_page', 'pr_type' ) ),
-                                               array( 'pr_page' => $id,
+                                       $dbw->insert(
+                                               'page_restrictions',
+                                               array(
+                                                       'pr_id' => $dbw->nextSequenceValue( 'page_restrictions_pr_id_seq' ),
+                                                       'pr_page' => $id,
                                                        'pr_type' => $action,
                                                        'pr_level' => $restrictions,
                                                        'pr_cascade' => ( $cascade && $action == 'edit' ) ? 1 : 0,
@@ -2401,9 +2417,7 @@ class WikiPage implements Page, IDBAccessObject {
                                                ),
                                                __METHOD__
                                        );
-                               } else {
-                                       $dbw->delete( 'page_restrictions', array( 'pr_page' => $id,
-                                               'pr_type' => $action ), __METHOD__ );
+                                       $logRelationsValues[] = $dbw->insertId();
                                }
                        }
 
@@ -2456,7 +2470,10 @@ class WikiPage implements Page, IDBAccessObject {
 
                // Update the protection log
                $log = new LogPage( 'protect' );
-               $log->addEntry( $logAction, $this->mTitle, $reason, $params, $user );
+               $logId = $log->addEntry( $logAction, $this->mTitle, $reason, $params, $user );
+               if ( $logRelationsField !== null && count( $logRelationsValues ) ) {
+                       $log->addRelations( $logRelationsField, $logRelationsValues, $logId );
+               }
 
                return Status::newGood();
        }
index f329b73..89ac734 100644 (file)
@@ -84,8 +84,10 @@ class ExternalStoreMwstore extends ExternalStoreMedium {
                        // Segregate items by wiki ID for the sake of bookkeeping
                        $wiki = isset( $this->params['wiki'] ) ? $this->params['wiki'] : wfWikiID();
 
-                       $url = $be->getContainerStoragePath( 'data' ) . '/' .
-                               rawurlencode( $wiki ) . "/{$rand[0]}/{$rand[1]}/{$rand[2]}/{$id}";
+                       $url = $be->getContainerStoragePath( 'data' ) . '/' . rawurlencode( $wiki );
+                       $url .= ( $be instanceof FSFileBackend )
+                               ? "/{$rand[0]}/{$rand[1]}/{$rand[2]}/{$id}" // keep directories small
+                               : "/{$rand[0]}/{$rand[1]}/{$id}"; // container sharding is only 2-levels
 
                        $be->prepare( array( 'dir' => dirname( $url ), 'noAccess' => 1, 'noListing' => 1 ) );
                        if ( $be->create( array( 'dst' => $url, 'content' => $data ) )->isOK() ) {
index 09284d0..e505ecb 100644 (file)
@@ -38,6 +38,7 @@ class SpecialProtectedpages extends SpecialPage {
        public function execute( $par ) {
                $this->setHeaders();
                $this->outputHeader();
+               $this->getOutput()->addModuleStyles( 'mediawiki.special' );
 
                // Purge expired entries on one in every 10 queries
                if ( !mt_rand( 0, 10 ) ) {
@@ -81,7 +82,7 @@ class SpecialProtectedpages extends SpecialPage {
                if ( $pager->getNumRows() ) {
                        $this->getOutput()->addHTML(
                                $pager->getNavigationBar() .
-                                       '<ul>' . $pager->getBody() . '</ul>' .
+                                       $pager->getBody() .
                                        $pager->getNavigationBar()
                        );
                } else {
@@ -89,105 +90,6 @@ class SpecialProtectedpages extends SpecialPage {
                }
        }
 
-       /**
-        * Callback function to output a restriction
-        * @param Title $row Protected title
-        * @return string Formatted "<li>" element
-        */
-       public function formatRow( $row ) {
-               wfProfileIn( __METHOD__ );
-
-               static $infinity = null;
-
-               if ( is_null( $infinity ) ) {
-                       $infinity = wfGetDB( DB_SLAVE )->getInfinity();
-               }
-
-               $title = Title::makeTitleSafe( $row->page_namespace, $row->page_title );
-               if ( !$title ) {
-                       wfProfileOut( __METHOD__ );
-
-                       return Html::rawElement(
-                               'li',
-                               array(),
-                               Html::element(
-                                       'span',
-                                       array( 'class' => 'mw-invalidtitle' ),
-                                       Linker::getInvalidTitleDescription(
-                                               $this->getContext(),
-                                               $row->page_namespace,
-                                               $row->page_title
-                                       )
-                               )
-                       ) . "\n";
-               }
-
-               $link = Linker::link( $title );
-
-               $description_items = array();
-
-               // Messages: restriction-level-sysop, restriction-level-autoconfirmed
-               $protType = $this->msg( 'restriction-level-' . $row->pr_level )->escaped();
-
-               $description_items[] = $protType;
-
-               if ( $row->pr_cascade ) {
-                       $description_items[] = $this->msg( 'protect-summary-cascade' )->text();
-               }
-
-               $stxt = '';
-               $lang = $this->getLanguage();
-
-               $expiry = $lang->formatExpiry( $row->pr_expiry, TS_MW );
-               if ( $expiry != $infinity ) {
-                       $user = $this->getUser();
-                       $description_items[] = $this->msg(
-                               'protect-expiring-local',
-                               $lang->userTimeAndDate( $expiry, $user ),
-                               $lang->userDate( $expiry, $user ),
-                               $lang->userTime( $expiry, $user )
-                       )->escaped();
-               }
-
-               if ( !is_null( $size = $row->page_len ) ) {
-                       $stxt = $lang->getDirMark() . ' ' . Linker::formatRevisionSize( $size );
-               }
-
-               // Show a link to the change protection form for allowed users otherwise
-               // a link to the protection log
-               if ( $this->getUser()->isAllowed( 'protect' ) ) {
-                       $changeProtection = Linker::linkKnown(
-                               $title,
-                               $this->msg( 'protect_change' )->escaped(),
-                               array(),
-                               array( 'action' => 'unprotect' )
-                       );
-               } else {
-                       $ltitle = SpecialPage::getTitleFor( 'Log' );
-                       $changeProtection = Linker::linkKnown(
-                               $ltitle,
-                               $this->msg( 'protectlogpage' )->escaped(),
-                               array(),
-                               array(
-                                       'type' => 'protect',
-                                       'page' => $title->getPrefixedText()
-                               )
-                       );
-               }
-
-               $changeProtection = ' ' . $this->msg( 'parentheses' )->rawParams( $changeProtection )
-                       ->escaped();
-
-               wfProfileOut( __METHOD__ );
-
-               return Html::rawElement(
-                       'li',
-                       array(),
-                       $lang->specialList( $link . $stxt, $lang->commaList( $description_items ), false ) .
-                               $changeProtection
-               ) . "\n";
-       }
-
        /**
         * @param int $namespace
         * @param string $type Restriction type
@@ -388,7 +290,7 @@ class SpecialProtectedpages extends SpecialPage {
  * @todo document
  * @ingroup Pager
  */
-class ProtectedPagesPager extends AlphabeticPager {
+class ProtectedPagesPager extends TablePager {
        public $mForm, $mConds;
        private $type, $level, $namespace, $sizetype, $size, $indefonly, $cascadeonly, $noredirect;
 
@@ -408,19 +310,185 @@ class ProtectedPagesPager extends AlphabeticPager {
                parent::__construct( $form->getContext() );
        }
 
-       function getStartBody() {
+       function preprocessResults( $result ) {
                # Do a link batch query
                $lb = new LinkBatch;
-               foreach ( $this->mResult as $row ) {
+               $userids = array();
+
+               foreach ( $result as $row ) {
                        $lb->add( $row->page_namespace, $row->page_title );
+                       // field is nullable, maybe null on old protections
+                       if ( $row->log_user !== null ) {
+                               $userids[] = $row->log_user;
+                       }
+               }
+
+               // fill LinkBatch with user page and user talk
+               if ( count( $userids ) ) {
+                       $userCache = UserCache::singleton();
+                       $userCache->doQuery( $userids, array(), __METHOD__ );
+                       foreach ( $userids as $userid ) {
+                               $name = $userCache->getProp( $userid, 'name' );
+                               if ( $name !== false ) {
+                                       $lb->add( NS_USER, $name );
+                                       $lb->add( NS_USER_TALK, $name );
+                               }
+                       }
                }
+
                $lb->execute();
+       }
 
-               return '';
+       function getFieldNames() {
+               static $headers = null;
+
+               if ( $headers == array() ) {
+                       $headers = array(
+                               'log_timestamp' => 'protectedpages-timestamp',
+                               'pr_page' => 'protectedpages-page',
+                               'pr_expiry' => 'protectedpages-expiry',
+                               'log_user' => 'protectedpages-performer',
+                               'pr_params' => 'protectedpages-params',
+                               'log_comment' => 'protectedpages-reason',
+                       );
+                       foreach ( $headers as $key => $val ) {
+                               $headers[$key] = $this->msg( $val )->text();
+                       }
+               }
+
+               return $headers;
        }
 
-       function formatRow( $row ) {
-               return $this->mForm->formatRow( $row );
+       /**
+        * @param string $field
+        * @param string $value
+        * @return string
+        * @throws MWException
+        */
+       function formatValue( $field, $value ) {
+               /** @var $row object */
+               $row = $this->mCurrentRow;
+
+               $formatted = '';
+
+               switch ( $field ) {
+                       case 'log_timestamp':
+                               // when timestamp is null, this is a old protection row
+                               if ( $value === null ) {
+                                       $formatted = Html::rawElement(
+                                               'span',
+                                               array( 'class' => 'mw-protectedpages-unknown' ),
+                                               $this->msg( 'protectedpages-unknown-timestamp' )->escaped()
+                                       );
+                               } else {
+                                       $formatted = $this->getLanguage()->userTimeAndDate( $value, $this->getUser() );
+                               }
+                               break;
+
+                       case 'pr_page':
+                               $title = Title::makeTitleSafe( $row->page_namespace, $row->page_title );
+                               if ( !$title ) {
+                                       $formatted = Html::element(
+                                               'span',
+                                               array( 'class' => 'mw-invalidtitle' ),
+                                               Linker::getInvalidTitleDescription(
+                                                       $this->getContext(),
+                                                       $row->page_namespace,
+                                                       $row->page_title
+                                               )
+                                       );
+                               } else {
+                                       $formatted = Linker::link( $title );
+                               }
+                               if ( !is_null( $row->page_len ) ) {
+                                       $formatted .= $this->getLanguage()->getDirMark() .
+                                               ' ' . Html::rawElement(
+                                               'span',
+                                               array( 'class' => 'mw-protectedpages-length' ),
+                                               Linker::formatRevisionSize( $row->page_len )
+                                       );
+                               }
+                               break;
+
+                       case 'pr_expiry':
+                               $formatted = $this->getLanguage()->formatExpiry( $value, /* User preference timezone */true );
+                               $title = Title::makeTitleSafe( $row->page_namespace, $row->page_title );
+                               if ( $this->getUser()->isAllowed( 'protect' ) && $title ) {
+                                       $changeProtection = Linker::linkKnown(
+                                               $title,
+                                               $this->msg( 'protect_change' )->escaped(),
+                                               array(),
+                                               array( 'action' => 'unprotect' )
+                                       );
+                                       $formatted .= ' ' . Html::rawElement(
+                                               'span',
+                                               array( 'class' => 'mw-protectedpages-actions' ),
+                                               $this->msg( 'parentheses' )->rawParams( $changeProtection )->escaped()
+                                       );
+                               }
+                               break;
+
+                       case 'log_user':
+                               // when timestamp is null, this is a old protection row
+                               if ( $row->log_timestamp === null ) {
+                                       $formatted = Html::rawElement(
+                                               'span',
+                                               array( 'class' => 'mw-protectedpages-unknown' ),
+                                               $this->msg( 'protectedpages-unknown-performer' )->escaped()
+                                       );
+                               } else {
+                                       $username = UserCache::singleton()->getProp( $value, 'name' );
+                                       if ( LogEventsList::userCanBitfield( $row->log_deleted, LogPage::DELETED_USER, $this->getUser() ) ) {
+                                               if ( $username === false ) {
+                                                       $formatted = htmlspecialchars( $value );
+                                               } else {
+                                                       $formatted = Linker::userLink( $value, $username )
+                                                               . Linker::userToolLinks( $value, $username );
+                                               }
+                                       } else {
+                                               $formatted = $this->msg( 'rev-deleted-user' )->escaped();
+                                       }
+                                       if ( LogEventsList::isDeleted( $row, LogPage::DELETED_USER ) ) {
+                                               $formatted = '<span class="history-deleted">' . $formatted . '</span>';
+                                       }
+                               }
+                               break;
+
+                       case 'pr_params':
+                               $params = array();
+                               // Messages: restriction-level-sysop, restriction-level-autoconfirmed
+                               $params[] = $this->msg( 'restriction-level-' . $row->pr_level )->escaped();
+                               if ( $row->pr_cascade ) {
+                                       $params[] = $this->msg( 'protect-summary-cascade' )->text();
+                               }
+                               $formatted = $this->getLanguage()->commaList( $params );
+                               break;
+
+                       case 'log_comment':
+                               // when timestamp is null, this is a old protection row
+                               if ( $row->log_timestamp === null ) {
+                                       $formatted = Html::rawElement(
+                                               'span',
+                                               array( 'class' => 'mw-protectedpages-unknown' ),
+                                               $this->msg( 'protectedpages-unknown-reason' )->escaped()
+                                       );
+                               } else {
+                                       if ( LogEventsList::userCanBitfield( $row->log_deleted, LogPage::DELETED_COMMENT, $this->getUser() ) ) {
+                                               $formatted = Linker::formatComment( $value !== null ? $value : '' );
+                                       } else {
+                                               $formatted = $this->msg( 'rev-deleted-comment' )->escaped();
+                                       }
+                                       if ( LogEventsList::isDeleted( $row, LogPage::DELETED_COMMENT ) ) {
+                                               $formatted = '<span class="history-deleted">' . $formatted . '</span>';
+                                       }
+                               }
+                               break;
+
+                       default:
+                               throw new MWException( "Unknown field '$field'" );
+               }
+
+               return $formatted;
        }
 
        function getQueryInfo() {
@@ -455,14 +523,51 @@ class ProtectedPagesPager extends AlphabeticPager {
                }
 
                return array(
-                       'tables' => array( 'page_restrictions', 'page' ),
-                       'fields' => array( 'pr_id', 'page_namespace', 'page_title', 'page_len',
-                               'pr_type', 'pr_level', 'pr_expiry', 'pr_cascade' ),
-                       'conds' => $conds
+                       'tables' => array( 'page', 'page_restrictions', 'log_search', 'logging' ),
+                       'fields' => array(
+                               'pr_id',
+                               'page_namespace',
+                               'page_title',
+                               'page_len',
+                               'pr_type',
+                               'pr_level',
+                               'pr_expiry',
+                               'pr_cascade',
+                               'log_timestamp',
+                               'log_user',
+                               'log_comment',
+                               'log_deleted',
+                       ),
+                       'conds' => $conds,
+                       'join_conds' => array(
+                               'log_search' => array(
+                                       'LEFT JOIN', array(
+                                               'ls_field' => 'pr_id', 'ls_value = pr_id'
+                                       )
+                               ),
+                               'logging' => array(
+                                       'LEFT JOIN', array(
+                                               'ls_log_id = log_id'
+                                       )
+                               )
+                       )
                );
        }
 
+       public function getTableClass() {
+               return 'TablePager mw-protectedpages';
+       }
+
        function getIndexField() {
                return 'pr_id';
        }
+
+       function getDefaultSort() {
+               return 'pr_id';
+       }
+
+       function isFieldSortable( $field ) {
+               // no index for sorting exists
+               return false;
+       }
 }
index 76959a1..bd84c72 100644 (file)
@@ -1931,7 +1931,7 @@ Alcuérdate de comprobar otros enllaces a les plantíes enantes d'esborrales.",
 'statistics-edits' => "Ediciones de páxines dende qu'entamó {{SITENAME}}",
 'statistics-edits-average' => "Media d'ediciones por páxina",
 'statistics-views-total' => 'Visites totales',
-'statistics-views-total-desc' => "Les vistes de páxines non-esistentes y especiales nun s'incluyen",
+'statistics-views-total-desc' => "Nun s'incluyen les visites a les páxines inesistentes y especiales",
 'statistics-views-peredit' => 'Visites por edición',
 'statistics-users' => '[[Special:ListUsers|Usuarios]] rexistraos',
 'statistics-users-active' => 'Usuarios activos',
@@ -2078,8 +2078,8 @@ Pues filtrar la visualización seleicionando una mena de rexistru, el nome d'usu
 
 # Special:Categories
 'categories' => 'Categoríes',
-'categoriespagetext' => "{{PLURAL:$1|La categoría darréu contién|Les categoríes darréu contienen}} páxines o ficheros multimedia.
-Les [[Special:UnusedCategories|categoríes non usaes]] nun s'amuesen equí.
+'categoriespagetext' => "{{PLURAL:$1|La siguiente categoría contién|Les siguientes categoríes contienen}} páxines o ficheros multimedia.
+Les [[Special:UnusedCategories|categoríes nun usaes]] nun s'amuesen equí.
 Ver tamién les [[Special:WantedCategories|categoríes más buscaes]].",
 'categoriesfrom' => "Amosar categoríes qu'emprimen por:",
 'special-categories-sort-count' => 'ordenar por tamañu',
@@ -2774,6 +2774,7 @@ $2",
 'thumbnail_image-type' => "Triba d'imaxe ensin sofitu",
 'thumbnail_gd-library' => 'Configuración incompleta de la biblioteca GD: falta la función $1',
 'thumbnail_image-missing' => "Paez que falta'l ficheru: $1",
+'thumbnail_image-failure-limit' => 'Hebo demasiaos intentos recientes que fallaron ($1 o más) al representar esta miniatura. Vuelva a intentalo más sero.',
 
 # Special:Import
 'import' => 'Importar páxines',
index 25f654b..f061612 100644 (file)
@@ -2913,6 +2913,7 @@ $1',
 'allmessages-prefix' => 'Фільтар па прэфіксе:',
 'allmessages-language' => 'Мова:',
 'allmessages-filter-submit' => 'Паказаць',
+'allmessages-filter-translate' => 'Перакласьці',
 
 # Thumbnails
 'thumbnail-more' => 'Павялічыць',
@@ -2967,7 +2968,7 @@ $2',
 Не стае часовай дырэкторыі.',
 'import-parse-failure' => 'Памылка разбору XML пры імпартаваньні',
 'import-noarticle' => 'Няма старонкі для імпартаваньня!',
-'import-nonewrevisions' => 'УÑ\81е Ð²Ñ\8dÑ\80Ñ\81Ñ\96Ñ\96 Ð±Ñ\8bлÑ\96 Ñ\96мпаÑ\80Ñ\82аванÑ\8bÑ\8f Ñ\80аней.',
+'import-nonewrevisions' => 'Ð\9dÑ\96Ñ\8fкÑ\96Ñ\8f Ð¿Ñ\80аÑ\9eкÑ\96 Ð½Ðµ Ð±Ñ\8bлÑ\96 Ñ\96мпаÑ\80Ñ\82аванÑ\8bÑ\8f (Ñ\83Ñ\81е Ñ\9eжо Ð°Ð±Ð¾ Ð±Ñ\8bлÑ\96 Ð°Ð¿Ñ\80аÑ\86аванÑ\8bÑ\8f, Ð°Ð±Ð¾ Ð¿Ñ\80апÑ\83Ñ\88Ñ\87анÑ\8bÑ\8f Ð¿Ñ\80аз Ð¿Ð°Ð¼Ñ\8bлкÑ\96).',
 'xml-error-string' => '$1 у радку $2, пазыцыі $3 (байт $4): $5',
 'import-upload' => 'Загрузіць XML-зьвесткі',
 'import-token-mismatch' => 'Страчаныя зьвесткі сэсіі. Калі ласка, паспрабуйце ізноў.',
index df6c555..d0fa1a1 100644 (file)
@@ -2339,6 +2339,14 @@ Jede Zeile enthält Links zur ersten und zweiten Weiterleitung sowie dem Ziel de
 'protectedpages-cascade' => 'Nur Seiten mit Kaskadenschutz',
 'protectedpages-noredirect' => 'Weiterleitungen ausblenden',
 'protectedpagesempty' => 'Aktuell sind keine Seiten mit diesen Parametern geschützt.',
+'protectedpages-timestamp' => 'Zeitstempel',
+'protectedpages-page' => 'Seite',
+'protectedpages-expiry' => 'Gültig bis',
+'protectedpages-performer' => 'Geschützt von',
+'protectedpages-params' => 'Schutzparameter',
+'protectedpages-reason' => 'Grund',
+'protectedpages-unknown-timestamp' => 'Unbekannt',
+'protectedpages-unknown-performer' => 'Unbekannter Benutzer',
 'protectedtitles' => 'Geschützte Seitennamen',
 'protectedtitlesempty' => 'Zurzeit sind mit den angegebenen Parametern keine Seiten zur Neuerstellung gesperrt.',
 'listusers' => 'Benutzerverzeichnis',
@@ -3084,6 +3092,7 @@ $2',
 'thumbnail_image-type' => 'Bildtyp nicht unterstützt',
 'thumbnail_gd-library' => 'Unvollständige Konfiguration der GD-Bibliothek: Fehlende Funktion $1',
 'thumbnail_image-missing' => 'Datei scheint fehlend zu sein: $1',
+'thumbnail_image-failure-limit' => 'Es wurden in letzter Zeit zu viele Versuche ($1 oder mehr) unternommen, dieses Vorschaubild zu rendern. Bitte versuche es später erneut.',
 
 # Special:Import
 'import' => 'Seiten importieren',
index 5e92d3d..d5198b6 100644 (file)
@@ -2767,6 +2767,15 @@ It now redirects to [[$2]].',
 'protectedpages-cascade'          => 'Cascading protections only',
 'protectedpages-noredirect'       => 'Hide redirects',
 'protectedpagesempty'             => 'No pages are currently protected with these parameters.',
+'protectedpages-timestamp'        => 'Timestamp',
+'protectedpages-page'             => 'Page',
+'protectedpages-expiry'           => 'Expires',
+'protectedpages-performer'        => 'Protecting user',
+'protectedpages-params'           => 'Protection parameters',
+'protectedpages-reason'           => 'Reason',
+'protectedpages-unknown-timestamp' => 'Unknown',
+'protectedpages-unknown-performer' => 'Unknown user',
+'protectedpages-unknown-reason'   => '—', # do not translate or duplicate this message to other languages
 'protectedtitles'                 => 'Protected titles',
 'protectedtitles-summary'         => '', # do not translate or duplicate this message to other languages
 'protectedtitlesempty'            => 'No titles are currently protected with these parameters.',
index 256c3e9..c36ae28 100644 (file)
@@ -715,6 +715,7 @@ $2',
 'customjsprotected' => 'Vi ne rajtas redakti ĉi tiun Ĝavaskriptan paĝon, ĉar ĝi enhavas personajn alĝustigojn de alia uzanto.',
 'mycustomcssprotected' => 'Vi ne havas la rajton redakti tiun ĉi CSS-paĝon.',
 'mycustomjsprotected' => 'Vi ne havas la rajton redakti tiun ĉi JavaScript-paĝon.',
+'mypreferencesprotected' => 'Vi ne havas permeson por redakti viajn preferojn.',
 'ns-specialprotected' => 'Paĝoj en la {{ns:special}} nomspaco ne povas esti redaktataj.',
 'titleprotected' => "Ĉi tiu titolo estas protektita de kreado de [[User:$1|$1]].
 La kialo donata estis ''$2''.",
@@ -774,7 +775,11 @@ Ne forgesu ŝanĝi viajn [[Special:Preferences|{{SITENAME}}-preferojn]]',
 'userlogin-resetpassword-link' => 'Ĉu vi forgesis vian pasvorton?',
 'helplogin-url' => 'Help:Ensalutado',
 'userlogin-helplink' => '[[{{MediaWiki:helplogin-url}}|Helpo pri ensalutado]]',
+'userlogin-loggedin' => 'Vi jam estas ensalutita kiel {{GENDER:$1|$1}}.
+Uzu la formularon suben por ensaluti kiel alia uzanto.',
+'userlogin-createanother' => 'Krei alian konton',
 'createacct-join' => 'Suben enigu informojn pri vi',
+'createacct-another-join' => 'Enigu la informon de la nova konto suben.',
 'createacct-emailrequired' => 'Retpoŝta adreso',
 'createacct-emailoptional' => 'Retpoŝta adreso (nedeviga)',
 'createacct-email-ph' => 'Enigu vian retpoŝtan adreson',
@@ -889,6 +894,7 @@ Vi eble jam ŝanĝis vian pasvorton aŭ petis novan provizoran pasvorton.',
 # Special:PasswordReset
 'passwordreset' => 'Restarigo de pasvorto',
 'passwordreset-text-one' => 'Plenigu ĉi tiun formularon por renovigi vian pasvorton.',
+'passwordreset-text-many' => '{{PLURAL:$1|Plenumu unu el la kampoj por restarigi vian pasvorton.}}',
 'passwordreset-legend' => 'Refari pasvorton',
 'passwordreset-disabled' => 'Pasvortaj restarigoj estis malŝaltitaj en ĉi tiu vikio.',
 'passwordreset-emaildisabled' => 'Retpoŝtaj funkcioj estas malfunkciigitaj en tiu ĉi vikio.',
@@ -1630,6 +1636,7 @@ indekso pro troŝarĝita servilo. Intertempe, vi povas serĉi per <i>guglo</i> a
 'right-viewmywatchlist' => 'Rigardi vian atentaron',
 'right-viewmyprivateinfo' => 'Vidi viajn proprajn privatajn informojn (ekz. retpoŝtan adreson, veran nomon)',
 'right-editmyprivateinfo' => 'Redakti viajn proprajn privatajn informojn (ekz. retpoŝtan adreson, veran nomon)',
+'right-editmyoptions' => 'Redakti proprajn preferojn',
 'right-rollback' => 'Tuj malfari la redaktojn de la lasta uzanto kiu redaktis specifan paĝon',
 'right-markbotedits' => 'Marki restarigitajn redaktojn kiel robotajn redaktojn',
 'right-noratelimit' => 'Ne influita de po-limoj',
@@ -1993,6 +2000,7 @@ Kiam oni filtras ĝin laŭ uzanto, nur la aktuala versio de la dosiero estos mon
 'listfiles_size' => 'Grandeco',
 'listfiles_description' => 'Priskribo',
 'listfiles_count' => 'Versioj',
+'listfiles-show-all' => 'Inkluzivi malaktualajn versiojn de bildoj',
 'listfiles-latestversion' => 'Nuna versio',
 'listfiles-latestversion-yes' => 'Jes',
 'listfiles-latestversion-no' => 'Ne',
@@ -2095,7 +2103,8 @@ Bonvolu kontroli aliajn ligilojn al la ŝablonoj antaŭ ol forigi ilin.',
 'randomincategory' => 'Hazarda paĝo en kategorio',
 'randomincategory-invalidcategory' => '"$1" ne estas valida kategoria nomo.',
 'randomincategory-nopages' => 'Ne estas paĝoj en la kategorio [[:Category:$1|$1]].',
-'randomincategory-selectcategory-submit' => 'Ek',
+'randomincategory-selectcategory' => 'Iri al hazarda paĝo el kategorio: $1 $2.$1',
+'randomincategory-selectcategory-submit' => 'Ek!',
 
 # Random redirect
 'randomredirect' => 'Hazarda alidirekto',
@@ -2936,6 +2945,8 @@ se vi volus kontribui al la komuna MediaWiki-asimilado.',
 'thumbnail-more' => 'Pligrandigi',
 'filemissing' => 'Mankanta dosiero',
 'thumbnail_error' => 'Okazis eraro ĉe kreado de antaŭvida bildeto: $1',
+'thumbnail_error_remote' => 'Eraro-mesaĝo de $1:
+$2',
 'djvu_page_error' => 'DjVu-a paĝo el intervalo',
 'djvu_no_xml' => 'Ne povas akiri XML por DjVu dosiero',
 'thumbnail-temp-create' => 'Ne povas krei provizoran bildetan dosieron',
@@ -3268,6 +3279,14 @@ $1',
 'hours-ago' => 'antaŭ $1 {{PLURAL:$1|horo|horoj}}',
 'minutes-ago' => 'antaŭ $1 {{PLURAL:$1|minuto|minutoj}}',
 'seconds-ago' => 'antaŭ $1 {{PLURAL:$1|sekundo|sekundoj}}',
+'monday-at' => 'Lundo je $1',
+'tuesday-at' => 'Mardo je $1',
+'wednesday-at' => 'Merkredo je $1',
+'thursday-at' => 'Ĵaŭdo je $1',
+'friday-at' => 'Vendredo je $1',
+'saturday-at' => 'Sabato je $1',
+'sunday-at' => 'Dimanĉo je $1',
+'yesterday-at' => 'Hieraŭ je $1',
 
 # Bad image list
 'bad_image_list' => 'La formato estas jen:
@@ -3924,6 +3943,7 @@ Vi povas ankaŭ [[Special:EditWatchlist|redakti norme]].',
 'version-license' => 'Permesilo de MediaWiki',
 'version-poweredby-credits' => "Ĉi tiu vikio funkcias per '''[https://www.mediawiki.org/ MediaWiki]''', aŭtorrajto ©&thinsp;2001–$1 $2.",
 'version-poweredby-others' => 'aliaj',
+'version-poweredby-translators' => 'tradukantoj de translatewiki.net',
 'version-credits-summary' => 'Ni ŝatus agnoski la sekvajn personojn pro siaj kontribuoj al [[Special:Version|MediaWiki]].',
 'version-license-info' => 'MediaWiki estas libera programaro. Vi povas redistribui ĝin kaj/aŭ modifi ĝin sub la kondiĉoj de la GNU General Public Licens (GNU Ĝenerala Publika Permesilo) en ties eldono de la Free Software Foundation (Libera Softvara Fondaĵo) - aŭ versio 2 de la Permesilo, aŭ (laŭ via elekto) iu ajn posta versio.
 
@@ -3939,6 +3959,7 @@ Oni devis doni al vi [{{SERVER}}{{SCRIPTPATH}}/COPYING ekzempleron de la GNU Gen
 
 # Special:Redirect
 'redirect-submit' => 'Ek',
+'redirect-lookup' => 'Traserĉi:',
 'redirect-value' => 'Valoro:',
 'redirect-user' => 'Salutnomo',
 'redirect-revision' => 'Revizio de la paĝo',
@@ -4038,6 +4059,7 @@ Oni devis doni al vi [{{SERVER}}{{SCRIPTPATH}}/COPYING ekzempleron de la GNU Gen
 'htmlform-selectorother-other' => 'Alia',
 'htmlform-no' => 'Ne',
 'htmlform-yes' => 'Jes',
+'htmlform-chosen-placeholder' => 'Elektu opcion',
 
 # SQLite database support
 'sqlite-has-fts' => '$1 kun tut-teksta subteno',
@@ -4159,6 +4181,7 @@ Aŭ vi povas uzi la facilan formularon sube. Via komento estos aldonita al la pa
 'limitreport-cputime-value' => '$1 {{PLURAL:$1|sekundo|sekundoj}}',
 'limitreport-walltime-value' => '$1 {{PLURAL:$1|sekundo|sekundoj}}',
 'limitreport-postexpandincludesize-value' => '$1/$2 {{PLURAL:$2|bitoko|bitokoj}}',
+'limitreport-templateargumentsize-value' => '$1/$2 {{PLURAL:$2|bitoko|bitokoj}}',
 
 # Special:ExpandTemplates
 'expandtemplates' => 'Ampleksigi ŝablonojn',
index e98f7e2..a3d60f7 100644 (file)
@@ -1134,8 +1134,9 @@ Se on jo olemassa.',
 'invalid-content-data' => 'Virheellinen sisältö',
 'content-not-allowed-here' => 'Sivun [[$2]] sisältö ei voi olla tyyppiä $1.',
 'editwarning-warning' => 'Tältä sivulta poistuminen saattaa aiheuttaa kaikkien tekemiesi muutosten katoamisen.
-Jos olet kirjautuneena sisään, voit poistaa tämän varoituksen käytöstä asetuksissa osiossa "Muokkaus".',
+Jos olet kirjautunut sisään, voit poistaa tämän varoituksen käytöstä omien asetuksien osiossa "{{int:prefs-editing}}".',
 'editpage-notsupportedcontentformat-title' => 'Sisällön muotoa ei tueta',
+'editpage-notsupportedcontentformat-text' => 'Sisällön muotoa $1 ei tueta sisältömallilla $2.',
 
 # Content models
 'content-model-wikitext' => 'wikiteksti',
@@ -1169,6 +1170,7 @@ Nämä muuttujat on jätetty käsittelemättä.",
 Varmista alla olevasta vertailusta, että haluat saada aikaan tämän lopputuloksen, ja sen jälkeen tallenna alla näkyvät muutokset.',
 'undo-failure' => 'Muokkausta ei voi kumota välissä olevien ristiriitaisten muutosten vuoksi.',
 'undo-norev' => 'Muokkausta ei voida kumota, koska sitä ei ole olemassa tai se on poistettu.',
+'undo-nochange' => 'Tämä muokkaus näyttää olevan jo kumottu.',
 'undo-summary' => 'Kumottu muokkaus $1, jonka teki [[Special:Contributions/$2|$2]] ([[User talk:$2|keskustelu]])',
 'undo-summary-username-hidden' => 'Kumottu muokkaus $1, jonka on tehnyt piilotettu käyttäjä',
 
@@ -1348,6 +1350,8 @@ Uuden ja vanhan sivun muutoksien pitää muodostaa jatkumo – ne eivät saa men
 'showhideselectedversions' => 'Näytä tai piilota valitut versiot',
 'editundo' => 'kumoa',
 'diff-empty' => '(ei eroavaisuuksia)',
+'diff-multi-sameuser' => '({{PLURAL:$1|Yhtä välissä olevaa versiota|$1 välissä olevaa versiota}} samalta käyttäjältä ei näytetä)',
+'diff-multi-otherusers' => '({{PLURAL:$1|Yhtä välissä olevaa versiota|$1 välissä olevaa versiota}} {{PLURAL:$2|toisen käyttäjän tekemänä|$2 käyttäjän tekeminä}} ei näytetä)',
 'diff-multi-manyusers' => '(Versioiden välissä on {{PLURAL:$1|yksi muu muokkaus|$1 muuta muokkausta, jotka on tehnyt {{PLURAL:$2|yksi käyttäjä|yli $2 eri käyttäjää}}}}.)',
 'difference-missing-revision' => '{{PLURAL:$2|Yhtä versiota|$2 versiota}} tästä vertailusta ($1) {{PLURAL:$2|ei}} löytynyt.
 
@@ -2975,7 +2979,7 @@ Tallenna tiedot koneellesi ja tuo ne tällä sivulla.',
 'importuploaderrortemp' => 'Tuontitiedoston tallennus epäonnistui. Väliaikaistiedostojen kansio puuttuu.',
 'import-parse-failure' => 'XML-tuonti epäonnistui jäsennysvirheen takia.',
 'import-noarticle' => 'Ei sivua tuotavaksi!',
-'import-nonewrevisions' => 'Kaikki versiot on tuotu aiemmin.',
+'import-nonewrevisions' => 'Ei tuotu yhtään versiota, koska kaikki versiot ovat jo täällä tai ne on ohitettu virheiden vuoksi.',
 'xml-error-string' => '$1 rivillä $2, sarakkeessa $3 (tavu $4): $5',
 'import-upload' => 'Tallenna XML-tiedosto',
 'import-token-mismatch' => 'Istuntotiedot ovat kadonneet. Yritä uudelleen.',
index 2d3b82b..879a47c 100644 (file)
@@ -3091,6 +3091,7 @@ $2",
 'thumbnail_image-type' => "Type d'image non supporté",
 'thumbnail_gd-library' => 'Configuration incomplète de la bibliothèque GD : fonction $1 introuvable',
 'thumbnail_image-missing' => 'Le fichier suivant est introuvable : $1',
+'thumbnail_image-failure-limit' => 'Il y a eu récemment trop de tentatives échouées ($1 ou plus) pour restituer cette vignette. Veuillez réessayer ultérieurement.',
 
 # Special:Import
 'import' => 'Importer des pages',
index db743dc..2f6d84e 100644 (file)
@@ -1629,7 +1629,7 @@ HTML टैग की जाँच करें।',
 'rclistfrom' => '$1 से नये बदलाव दिखाएँ',
 'rcshowhideminor' => 'छोटे बदलाव $1',
 'rcshowhidebots' => 'बॉट $1',
-'rcshowhideliu' => '$1 पंजीकृत सदस्य',
+'rcshowhideliu' => 'पंजीकृत सदस्य $1',
 'rcshowhideanons' => 'आइ॰पी सदस्यों के बदलाव $1',
 'rcshowhidepatr' => 'परीक्षित सम्पादन $1',
 'rcshowhidemine' => 'मेरे बदलाव $1',
@@ -3861,7 +3861,7 @@ $5
 'version-parser-function-hooks' => 'पार्सर कार्य हूक',
 'version-hook-name' => 'हूक नाम',
 'version-hook-subscribedby' => 'ने सदस्यत्व लिया',
-'version-version' => '(अवतरण $1)',
+'version-version' => '($1)',
 'version-license' => 'मीडियाविकि अनुज्ञापत्र',
 'version-ext-colheader-description' => 'विवरण',
 'version-ext-colheader-credits' => 'लेखक',
index c6285a8..b2ccd0f 100644 (file)
@@ -1379,7 +1379,7 @@ $1",
 'prefs-labs' => 'មុខងារពិសេសថ្មីៗដែលស្ថិតក្រោមការពិសោធន៍នៅឡើយ',
 'prefs-user-pages' => 'ទំព័រអ្នកប្រើប្រាស់',
 'prefs-personal' => 'ប្រវត្តិរូប',
-'prefs-rc' => 'á\9e\94á\9f\86á\9e\9bá\9e¶á\9e\9fá\9f\8bá\9e\94á\9f\92á\9e\8aá\9e¼á\9e\9aថ្មីៗ',
+'prefs-rc' => 'á\9e\94á\9e\93á\9f\92á\9e\9bá\9e¶á\9e\9fá\9f\8bâ\80\8bá\9e\94á\9f\92á\9e\8aá\9e¼á\9e\9aâ\80\8bថ្មីៗ',
 'prefs-watchlist' => 'បញ្ជីតាមដាន',
 'prefs-watchlist-days' => 'ចំនួនថ្ងៃត្រូវបង្ហាញក្នុងបញ្ជីតាមដាន៖',
 'prefs-watchlist-days-max' => 'អតិបរមា $1 {{PLURAL:$1|ថ្ងៃ|ថ្ងៃ}}',
index 9a0db2c..9e765b9 100644 (file)
@@ -731,7 +731,7 @@ URL을 잘못 입력하였거나, 잘못된 링크를 따라갔을 수 있습니
 'badtitletext' => '요청한 문서 제목이 잘못되었거나, 비어있거나, 잘못된 인터위키 제목으로 링크했습니다.
 문서 제목에 사용할 수 없는 문자를 사용했을 수 있습니다.',
 'perfcached' => '다음 자료는 캐시된 것이므로 새로 바뀐 내용을 반영하지 못할 수도 있습니다. 캐시에 최대 {{PLURAL:$1|$1개의 결과}}가 있습니다.',
-'perfcachedts' => '다음 자료는 캐시된 것으로, $1에 마지막으로 새로 고쳐졌습니다.  캐시에 최대 {{PLURAL:$4|결과 $4개}}가 있습니다.',
+'perfcachedts' => '다음 자료는 캐시된 것으로, $1에 마지막으로 새로 고쳐졌습니다. 캐시에 최대 {{PLURAL:$4|결과 $4개}}가 있습니다.',
 'querypage-no-updates' => '이 문서의 새로 고침이 현재 비활성화되어 있습니다.
 이 문서의 자료를 잠시 동안 새로 고치지 않을 것입니다.',
 'viewsource' => '원본 보기',
@@ -833,7 +833,7 @@ $2',
 'createacct-imgcaptcha-ph' => '위에 보이는 텍스트를 입력하세요',
 'createacct-submit' => '계정 만들기',
 'createacct-another-submit' => '다른 계정 만들기',
-'createacct-benefit-heading' => '{{SITENAME}}\9d\80\8a\94 ì\97¬ë\9f¬ë¶\84ê³¼ ê°\99ì\9d\80 ì\82¬ë\9e\8cì\9c¼ë¡\9c ì\9d´ë£¨ì\96´ì§\91ë\8b\88ë\8b¤.',
+'createacct-benefit-heading' => '{{SITENAME}} í\94\84ë¡\9cì \9dí\8a¸ë\8a\94 ì\97¬ë\9f¬ë¶\84ê³¼ ê°\99ì\9d\80 ì\82¬ë\9e\8cë\93¤ì\9d´ ë§\8cë\93¤ì\96´ ê°\91ë\8b\88ë\8b¤.',
 'createacct-benefit-body1' => '{{PLURAL:$1|편집}}',
 'createacct-benefit-body2' => '{{PLURAL:$1|문서}}',
 'createacct-benefit-body3' => '최근 {{PLURAL:$1|기여자}}',
@@ -1255,6 +1255,7 @@ $2개 보다 적게 {{PLURAL:$2|써야}} 하지만 {{PLURAL:$1|지금은 $1개
 편집 되돌리기를 완료하려면 이 편집을 되돌리려면 아래의 바뀐 내용을 확인한 후 저장해주세요.',
 'undo-failure' => '중간의 다른 편집과 충돌하여 이 편집을 되돌릴 수 없습니다.',
 'undo-norev' => '문서가 없거나 삭제되었기 때문에 편집을 되돌릴 수 없습니다.',
+'undo-nochange' => '편집이 이미 되돌려진 것으로 나타납니다.',
 'undo-summary' => '[[Special:Contributions/$2|$2]] ([[User talk:$2|토론]])의 $1판 편집을 되돌림',
 'undo-summary-username-hidden' => '숨겨진 사용자가 $1 판을 되돌림',
 
@@ -1485,7 +1486,8 @@ $1",
 'searchrelated' => '관련',
 'searchall' => '모두',
 'showingresults' => "'''$2'''번 부터의 {{PLURAL:$1|결과 '''1'''개|결과 '''$1'''개}}입니다.",
-'showingresultsnum' => "'''$2'''번 부터의 {{PLURAL:$3|결과 '''1'''개|결과 '''$3'''개}} 입니다.",
+'showingresultsinrange' => '#<strong>$2</strong>부터 #<strong>$3</strong>까지의 범위에서 <strong>$1</strong>개의 {{PLURAL:$1|결과}}가 아래에 보입니다.',
+'showingresultsnum' => "'''$2'''번 부터의 {{PLURAL:$3|결과 '''1'''개|결과 '''$3'''개}}입니다.",
 'showingresultsheader' => "'''$4''' 검색어에 대한 {{PLURAL:$5|결과 '''$3'''개 중 '''$1'''개|결과 '''$3'''개 중 '''$1 - $2'''번째}}",
 'search-nonefound' => '검색어와 일치하는 결과가 없습니다.',
 'powersearch-legend' => '고급 검색',
@@ -2254,7 +2256,7 @@ URL이 맞고 해당 웹사이트가 작동하는지 확인해주세요.',
 'pageswithprop-legend' => '문서 속성이 있는 문서',
 'pageswithprop-text' => '이 문서는 특정 문서 속성을 사용한 문서를 나타냅니다.',
 'pageswithprop-prop' => '속성 이름:',
-'pageswithprop-submit' => '기',
+'pageswithprop-submit' => '기',
 'pageswithprop-prophidden-long' => '숨겨진 긴 텍스트 속성 값 ($1)',
 'pageswithprop-prophidden-binary' => '숨겨진 이진 속성 값 ($1)',
 
@@ -4013,7 +4015,7 @@ $5
 
 # Friendlier slave lag warnings
 'lag-warn-normal' => '최근 $1{{PLURAL:$1|초}} 안에 바뀐 문서는 이 목록에서 빠졌을 수 있습니다.',
-'lag-warn-high' => 'ë\8d°ì\9d´í\84°ë² ì\9d´ì\8a¤ ì\84\9cë²\84ì\9d\98 ê³¼ë\8f\84í\95\9c ë¶\80í\95\98 ë\95\8c문ì\97\90 ìµ\9cê·¼ $1{{PLURAL:$1|ì´\88}} ì\95\88ì\97\90 ë°\94ë\80\90 ë¬¸ì\84\9c ëª©ë¡\9dì\9d\80 ë³´ì\97¬ì§\80지 않을 수 있습니다.',
+'lag-warn-high' => 'ë\8d°ì\9d´í\84°ë² ì\9d´ì\8a¤ ì\84\9cë²\84ì\9d\98 ê³¼ë\8f\84í\95\9c ë¶\80í\95\98 ë\95\8c문ì\97\90 ìµ\9cê·¼ $1{{PLURAL:$1|ì´\88}} ì\95\88ì\97\90 ë°\94ë\80\90 ë¬¸ì\84\9c ëª©ë¡\9dì\9d\80 ë³´ì\9d´지 않을 수 있습니다.',
 
 # Watchlist editor
 'watchlistedit-numitems' => '토론 문서를 제외하고 {{PLURAL:$1|문서 1개|문서 $1개}}를 주시하고 있습니다.',
index 7a846a6..ab7a9cb 100644 (file)
@@ -571,6 +571,7 @@ un doht em och de URL vun dä Sigg heh sage.',
 'cannotdelete-title' => 'Mer künne di Sigg „$1“ nit fott schmiiße.',
 'delete-hook-aborted' => 'Et Fottschmiiße wood affjebroche övver ene sujenannte „Hoke“ en de ẞoffwäer.
 Ene Jrond weße mer nit.',
+'no-null-revision' => 'Mer kunnte kein onveränderte neue Väsjohn vun dä Sigg „$1“ aanlääje.',
 'badtitle' => 'Verkihrte Üvverschreff',
 'badtitletext' => 'De Üvverschreff es esu nit en Odenung. Et muss jet dren stonn.
 Et künnt sin, dat ein vun de speziell Zeiche dren steiht,
@@ -623,7 +624,7 @@ Dä Wiki_Köbes dovun hät beim Deeschmaache als Jrond aanjejovve: „$3“',
 'invalidtitle-knownnamespace' => '„$3“ es ene onjöltijje Tittel för em Appachtemang „$2“',
 'invalidtitle-unknownnamespace' => '„$2“ es ene onjöltijje Tittel för e Appachtemang met dä verkehte Nommer $1.',
 'exception-nologin' => 'Nit enjelogg',
-'exception-nologin-text' => 'Heh di Sigg udder heh dä Opdraach jeiht blooß, wann De heh em Wiki enjelogg bes.',
+'exception-nologin-text' => 'Heh di Sigg udder heh dä Opdraach jeiht blooß, wann De heh [[Special:Userlogin|em Wiki enjelogg]] bes.',
 'exception-nologin-text-manual' => 'De mööds ald $1, öm heh di Sigg udder di Axjuhn zohjriife ze dörve.',
 
 # Virus scanner
@@ -674,7 +675,7 @@ Wann De wells, künnts De Ding [[Special:Preferences|Enschtällonge aanpaße]].'
 'userlogin-resetpassword-link' => 'Paßwoot verjäße?',
 'helplogin-url' => 'Help:Övver et Enlogge',
 'userlogin-helplink' => '[[{{MediaWiki:helplogin-url}}|Hölp bem Enlogge]]',
-'userlogin-loggedin' => 'Do bes ald als {{GENDER:$1|Metmaacher|Metmaacherėn|Metmaacher|Metmaacherėn|Metmaacher}} [[User:$1]] enjelogg. Met heh dämm Fommolaa kanns De jäz onger enem andere Nahme enlogge.',
+'userlogin-loggedin' => 'Do bes ald als {{GENDER:$1|dä Metmaacher|de Metmaacherėn|dä Metmaacher|de Metmaacherėn|däMetmaacher}} [[User:$1]] enjelogg. Met heh dämm Fommolaa kanns De jäz onger enem andere Nahme enlogge.',
 'userlogin-createanother' => 'Donn ene zohsäzlejje Zohjang aanlääje',
 'createacct-join' => 'Jiv Ding Daate en:',
 'createacct-another-join' => 'Maach de nüüdeje Aanjaabe för dä neue Zohjaang.',
@@ -817,6 +818,7 @@ Wann dä aanjejovve es, weet_e jebruch, öm öffentlesch de Schriiver för Beidr
 'retypenew' => 'Noch ens dat neue Passwood:',
 'resetpass_submit' => 'E neu Zweschepasswood övvermeddele un aanmellde',
 'changepassword-success' => 'Et Paßwood es jeändert.',
+'changepassword-throttled' => 'Do häs zoh öff versöhk, enzelogge. Waat $1 Ih dat De es widder probeers.',
 'resetpass_forbidden' => 'E Passwoot kann nit jeändert wääde.',
 'resetpass-no-info' => 'Do mööts ad enjelogg sin, öm tiräk op di Sigg jonn ze dörve',
 'resetpass-submit-loggedin' => 'Passwood tuusche',
@@ -882,6 +884,7 @@ Do moß Ding Paßwoot enjävve, öm Ding Änderong ze bschtäätejje.',
 'changeemail-password' => 'Ding Passwoot {{GRAMMAR:en 3|{{ucfirst:{{SITENAME}}}}}}:',
 'changeemail-submit' => 'Lohß jonn!',
 'changeemail-cancel' => 'Ophüre',
+'changeemail-throttled' => 'Do häs zoh öff versöhk, enzelogge. Waat $1 Ih dat De es widder probeers.',
 
 # Special:ResetTokens
 'resettokens-token-label' => '$1 (Em Momang es et: $2)',
@@ -1137,6 +1140,8 @@ Ene Jrond weße mer nit.',
 'content-not-allowed-here' => 'Ene Enhalld vun dä Zoot „$1“ es op dä Sigg „[[$2]]“ nit zohjelohße.',
 'editwarning-warning' => 'Wann de vun hee dä Sigg fott jeihß, doh künnte all Ding Änderonge aan dä Sigg verschött jonn.
 Do kanns heh di Warnung affschallde, wann de aanjemelldt un enjelogg bes, dann kriß de se nieh mieh wider. Jangk doför en dä Afschnett „{{int:prefs-editing}}“ en Dinge Enschtellonge.',
+'editpage-notsupportedcontentformat-title' => 'Dat Fommat vun enem Enhalld künne mer nit.',
+'editpage-notsupportedcontentformat-text' => 'Dat Fommat $1 vun enem Enhalld künne mer nit mem Modäll $2.',
 
 # Content models
 'content-model-wikitext' => 'Wikitäx',
@@ -1168,6 +1173,7 @@ Do kanns heh di Warnung affschallde, wann de aanjemelldt un enjelogg bes, dann k
 'undo-success' => 'De Änderung könnte mer zeröck nämme. Beloor Der de Ungerscheid un dann donn di Sigg avspeichere, wann De dengks, et es en Oodenung esu.',
 'undo-failure' => 'Dat kunnt mer nit zeröck nämme, dä Afschnedd wood enzwesche ald widder beärbeidt.',
 'undo-norev' => "Do ka'mer nix zeröck nämme. Di Version jidd_et nit, odder se es verstoche odder fottjeschmesse woode.",
+'undo-nochange' => 'Di Änderong schingk ald retuur jemaat woode ze sin.',
 'undo-summary' => 'De Änderung $1 fum [[Special:Contributions/$2|$2]] ([[User talk:$2|Klaaf]]) zeröck jenomme.',
 'undo-summary-username-hidden' => 'Nemm di Väsjohn $1 vun enem verschtoche Metmaacher widder retuur.',
 
@@ -1366,7 +1372,8 @@ Mieh doh drövver fengk mer em [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAG
 'shown-title' => 'Zeisch {{PLURAL:$1|ein|$1|nix}} pro Sigg',
 'viewprevnext' => 'Bläddere: ($1 {{int:pipe-separator}} $2) ($3).',
 'searchmenu-exists' => "*Sigg '''[[$1]]'''",
-'searchmenu-new' => "'''Donn de Sigg „[[:$1|$1]]“ hee em Wiki aanlääje'''",
+'searchmenu-new' => '<strong>Donn de Sigg „[[:$1|$1]]“ hee em Wiki aanlääje.</strong>
+{{PLURAL:$2|Beloor Der ävver och die Sigg, di beim Söhke jefonge wood.|Beloor Der ävver och die Sigge, di beim Söhke jefonge woode sin.|}}',
 'searchprofile-articles' => 'Sigge vum Enhalt',
 'searchprofile-project' => 'Hülp- ov Projäk-Sigge',
 'searchprofile-images' => 'Dateie met Medije',
@@ -3021,6 +3028,7 @@ Wenn De jenerell aan [https://www.mediawiki.org/wiki/Localisation MediaWiki sing
 'allmessages-prefix' => 'Name fängk aan met:',
 'allmessages-language' => 'Schprooch:',
 'allmessages-filter-submit' => 'Lohß Jonn!',
+'allmessages-filter-translate' => 'Övversäze!',
 
 # Thumbnails
 'thumbnail-more' => 'Jrößer aanzeije',
@@ -3237,6 +3245,7 @@ Esu kam_mer noch en Aanmärkong en „{{int:summary}}“ maache.',
 'pageinfo-length' => 'Bytes en dä Sigg',
 'pageinfo-article-id' => 'Dä Sigg ier Nommer en dä Daatebangk',
 'pageinfo-language' => 'De Schprooch vum Sigge-Enhallt',
+'pageinfo-content-model' => 'Et Modäll för der Enhalld vun dä Sigg',
 'pageinfo-robot-policy' => 'Et opnämme es för Söhkmaschiine',
 'pageinfo-robot-index' => 'zohjelohße',
 'pageinfo-robot-noindex' => 'verbodde',
@@ -4068,6 +4077,7 @@ Dä Shtanndat-Zoot-Schlößel „$1“ övverschriif dä älldere Zoot-Schlöße
 'version-ext-colheader-description' => 'Beschrevve',
 'version-ext-colheader-credits' => 'Schriiver',
 'version-license-title' => '‎Lėzänz för $1',
+'version-license-not-found' => 'Mer han kein Lezänzenfommazjuhne för heh dat Zohsazprojramm jefonge.',
 'version-poweredby-credits' => "Dat Wiki heh löp met '''[https://www.mediawiki.org/ MediaWiki]''', copyright © 2001–$1 $2.",
 'version-poweredby-others' => 'sönß wää',
 'version-poweredby-translators' => 'de Övversäzer em translatewiki.net',
@@ -4089,7 +4099,7 @@ Do sullts en [{{SERVER}}{{SCRIPTPATH}}/COPYING Kopie vun dä <i lang="en">GNU Ge
 # Special:Redirect
 'redirect' => 'Ömleide op en Dattei, ene Metmaacher udder de Väsjohn vun ener Sigg',
 'redirect-legend' => 'Ömleide ob_en Dattei udder Sigg',
-'redirect-summary' => 'Heh di {{int:specialpage}} leidt öm ob_en Dattei — doh mößd_Er ene Nahme aanjävve — udder en Sigg — doh mößd_Er en Kännong för en Väsjoh aanjävve — udder en Metmaachersigg — doh mößd_Er enem Metmaacher sing Kännong aanjävve.',
+'redirect-summary' => 'Heh di {{int:specialpage}} leidt öm ob_en Dattei — doh mößd_Er ene Nahme aanjävve, för e Beischpell:[[{{#Special:Redirect}}/file/Example.jpg]] — udder en Sigg — doh mößd_Er en Kännong för, udder en Väsjuhn aanjävve, för e Beischpell esu: [[{{#Special:Redirect}}/page/64308]] udder [[{{#Special:Redirect}}/revision/328429]] — udder en Metmaachersigg — doh mößd_Er enem Metmaacher sing Kännong aanjävve, för e Beischpell: [[{{#Special:Redirect}}/user/101]].',
 'redirect-submit' => 'Lohß Jonn!',
 'redirect-lookup' => 'Söhk noh:',
 'redirect-value' => 'Kännong udder Nahme:',
index 233205a..f09b546 100644 (file)
@@ -3089,6 +3089,7 @@ $2',
 'thumbnail_image-type' => 'Неподдржан тип на слика',
 'thumbnail_gd-library' => 'Нецелосни поставки на графичката библиотека: недостасува функцијата $1',
 'thumbnail_image-missing' => 'Изгледа дека податотеката недостасува: $1',
+'thumbnail_image-failure-limit' => 'Направив премногу обиди ($1 или повеќе) за да ја прикажам минијатурава. Обидете се подоцна.',
 
 # Special:Import
 'import' => 'Увезување на страници',
index baf86f0..ba5a5c7 100644 (file)
@@ -1375,6 +1375,7 @@ Użycie linków nawigacyjnych kasuje wybór w kolumnie.',
 'showhideselectedversions' => 'Pokaż lub ukryj zaznaczone wersje',
 'editundo' => 'anuluj edycję',
 'diff-empty' => '(Brak różnic)',
+'diff-multi-otherusers' => '(Nie pokazano $1 wersji {{PLURAL:$1|utworzonej|utworzonych}} przez {{PLURAL:$2|jednego użytkownika|$2 użytkowników}})',
 'diff-multi-manyusers' => '(Nie pokazano $1 {{PLURAL:$1|pośredniej wersji utworzonej|pośrednich wersji utworzonych}} przez {{PLURAL:$2|jednego użytkownika|$2 użytkowników}})',
 'difference-missing-revision' => '{{PLURAL:$2|Wersja|$2 wersje|$2 wersji}} #$1 strony "{{PAGENAME}}" nie {{PLURAL:$2|została znaleziona|zostały znalezione|zostało znalezionych}}.
 
index 7c6bf87..d833ab7 100644 (file)
@@ -1214,7 +1214,7 @@ Depois grave as alterações, para finalizar e desfazer a edição.',
 'cantcreateaccount-text' => "A criação de contas a partir deste endereço IP ('''$1''') foi bloqueada por [[User:$3|$3]].
 
 O motivo apresentado por $3 foi ''$2''",
-'cantcreateaccount-range-text' => "A criação de conta a partir dos Endereços IP no intervalo '''$1''', que inclui o seu Endereço IP ('''$4'''), foi bloqueado por [[User:$3|$3]].
+'cantcreateaccount-range-text' => "A criação de conta a partir dos endereços IP no intervalo '''$1''', que inclui o seu endereço IP ('''$4'''), foi bloqueada por [[User:$3|$3]].
 
 A razão dada por $3 é ''$2''",
 
index 5c6929e..b436dce 100644 (file)
@@ -47,6 +47,7 @@
  * @author Malafaya
  * @author ManoDbo
  * @author Matheus Sousa L.T
+ * @author Matma Rex
  * @author McDutchie
  * @author MetalBrasil
  * @author MisterSanderson
@@ -888,6 +889,8 @@ Se você optar por fornecê-lo, este nome será utilizado para dar ao usuário a
 'retypenew' => 'Reintroduza a nova senha',
 'resetpass_submit' => 'Definir senha e entrar',
 'changepassword-success' => 'Sua senha foi alterada com sucesso!',
+'changepassword-throttled' => 'Você realizou demasiadas tentativas de se registrar.
+Por favor, aguarde $1 antes de tentar novamente.',
 'resetpass_forbidden' => 'As senhas não podem ser alteradas',
 'resetpass-no-info' => 'Você precisa estar autenticado para acessar esta página diretamente.',
 'resetpass-submit-loggedin' => 'Alterar senha',
@@ -943,6 +946,8 @@ Senha temporária: $2',
 'changeemail-password' => 'Sua senha para o wiki {{SITENAME}}:',
 'changeemail-submit' => 'Alterar e-mail',
 'changeemail-cancel' => 'Cancelar',
+'changeemail-throttled' => 'Você realizou demasiadas tentativas de se registrar.
+Por favor, aguarde $1 antes de tentar novamente.',
 
 # Special:ResetTokens
 'resettokens' => 'Reiniciar os tokens',
@@ -1201,6 +1206,7 @@ Estes argumentos foram omitidos.',
 'undo-success' => 'A edição pôde ser desfeita. Por gentileza, verifique o comparativo a seguir para se certificar de que é isto que deseja fazer, salvando as alterações após ter terminado de revisá-las.',
 'undo-failure' => 'A edição não pôde ser desfeita devido a alterações intermediárias conflitantes.',
 'undo-norev' => 'A edição não pôde ser desfeita porque não existe ou foi apagada.',
+'undo-nochange' => 'Parece que a edição já foi desfeita.',
 'undo-summary' => 'Desfeita a edição $1 de [[Special:Contributions/$2|$2]] ([[User talk:$2|Discussão]])',
 'undo-summary-username-hidden' => 'Desfazer a revisão $1 de um usuário oculto',
 
@@ -1209,6 +1215,9 @@ Estes argumentos foram omitidos.',
 'cantcreateaccount-text' => "Este IP ('''$1''') foi bloqueado de criar novas contas por [[User:$3|$3]].
 
 A justificativa apresentada por $3 foi ''$2''",
+'cantcreateaccount-range-text' => "A criação de conta a partir dos endereços IP no intervalo '''$1''', que inclui o seu endereço IP ('''$4'''), foi bloqueada por [[User:$3|$3]].
+
+A razão dada por $3 é ''$2''",
 
 # History pages
 'viewpagelogs' => 'Ver registros para esta página',
@@ -1377,6 +1386,8 @@ Certifique-se de que tal alteração manterá a continuidade das ações.',
 'showhideselectedversions' => 'Exibir/ocultar edições selecionadas',
 'editundo' => 'desfazer',
 'diff-empty' => '(Sem diferença)',
+'diff-multi-sameuser' => '({{PLURAL:$1|Uma revisão intermediária|$1 revisões intermediárias}} pelo mesmo usuário não estão sendo mostradas)',
+'diff-multi-otherusers' => '({{PLURAL:$1|Uma revisão intermediária por {{PLURAL:$2|um outro usuário|$2 usuários}} não está sendo mostrada|$1 revisões intermediárias por {{PLURAL:$2|um outro usuário|$2 usuários}} não estão sendo mostradas}})',
 'diff-multi-manyusers' => '({{PLURAL:$1|Uma edição intermediária|$1 edições intermediárias}} de mais de {{PLURAL:$2|um usuário|$2 usuário}} não {{PLURAL:$1|apresentada|apresentadas}})',
 'difference-missing-revision' => '{{PLURAL:$2|Uma revisão|$2 revisões}} desta diferença ($1) não {{PLURAL:$2|foi encontrada|foram encontradas}}.
 
@@ -1413,6 +1424,7 @@ Os detalhes podem ser encontrados no [{{fullurl:{{#Special:Log}}/delete|page={{F
 'search-result-score' => 'Relevância: $1%',
 'search-redirect' => '(redirecionamento de $1)',
 'search-section' => '(seção $1)',
+'search-file-match' => '(coincide com o conteúdo do arquivo)',
 'search-suggest' => 'Você quis dizer: $1',
 'search-interwiki-caption' => 'Projetos irmãos',
 'search-interwiki-default' => 'Resultados de $1:',
@@ -2994,6 +3006,7 @@ Acesse [https://www.mediawiki.org/wiki/Localisation MediaWiki Localisation] e [/
 'allmessages-prefix' => 'Filtrar por prefixo:',
 'allmessages-language' => 'Língua:',
 'allmessages-filter-submit' => 'Ir',
+'allmessages-filter-translate' => 'Traduzir',
 
 # Thumbnails
 'thumbnail-more' => 'Ampliar',
@@ -4128,7 +4141,7 @@ Caso contrário, você poderá usar o formulário simplificado a seguir. Seu com
 'feedback-error1' => 'Erro: O resultado da API não foi reconhecido',
 'feedback-error2' => 'Erro: A edição falhou',
 'feedback-error3' => 'Erro: A API não responde',
-'feedback-thanks' => 'Obrigado! O seu comentário foi adicionado à página "[ $2  $1 ]".',
+'feedback-thanks' => 'Obrigado! O seu comentário foi adicionado à página "[$2 $1]".',
 'feedback-close' => 'Feito',
 'feedback-bugcheck' => 'Perfeito! Apenas verifique se não é um dos [$1 bugs já conhecidos].',
 'feedback-bugnew' => 'Eu verifiquei. Relatar um bug novo',
index b004b12..bedc036 100644 (file)
@@ -5013,6 +5013,17 @@ See the following search results:
 'protectedpages-noredirect' => 'Option in [[Special:ProtectedPages]].
 {{Identical|Hide redirect}}',
 'protectedpagesempty' => 'Used in [[Special:ProtectedPages]], when there are no protected pages with the specified parameters.',
+'protectedpages-timestamp' => 'This is a column header for dates and times in the table on the page [[Special:ProtectedPages]].
+{{Identical|Timestamp}}',
+'protectedpages-page' => 'This is a column header in the table on the page [[Special:ProtectedPages]].',
+'protectedpages-expiry' => 'This is a column header in the table on the page [[Special:ProtectedPages]].
+{{Identical|Expire}}',
+'protectedpages-performer' => 'This is a column header in the table on the page [[Special:ProtectedPages]].',
+'protectedpages-params' => 'This is a column header in the table on the page [[Special:ProtectedPages]].',
+'protectedpages-reason' => 'This is a column header in the table on the page [[Special:ProtectedPages]].
+{{Identical|Reason}}',
+'protectedpages-unknown-timestamp' => 'This is shown, when the date and time is unknown for a protection on the page [[Special:ProtectedPages]].',
+'protectedpages-unknown-performer' => 'This is shown, when the protecting user is unknown for a protection on the page [[Special:ProtectedPages]].',
 'protectedtitles' => '{{doc-special|ProtectedTitles}}',
 'protectedtitlesempty' => 'Used on [[Special:ProtectedTitles]]. This text appears if the list of protected titles is empty. See the [[mw:Project:Protected_titles|help page on MediaWiki]] for more information.',
 'listusers' => '{{doc-special|ListUsers}}',
@@ -7269,8 +7280,10 @@ See also:
 *$1 is a function name of the GD library',
 'thumbnail_image-missing' => 'This is the parameter 1 of the message {{msg-mw|thumbnail error}}.
 *$1 is the path incl. filename of the missing image',
-'thumbnail_image-failure-limit' => 'This is the parameter 1 of the message {{msg-mw|thumbnail error}}.
-*$1 is the maximum allowed number of failed attempts',
+'thumbnail_image-failure-limit' => 'Used as <code>$1</code> in {{msg-mw|Thumbnail error}}.
+
+Parameters:
+* $1 - the maximum allowed number of failed attempts',
 
 # Special:Import
 'import' => 'The title of the special page [[Special:Import]];',
index 74377cd..d9a322c 100644 (file)
@@ -2985,6 +2985,7 @@ $2',
 'thumbnail_image-type' => 'Acest tip de imagine nu este suportat',
 'thumbnail_gd-library' => 'Configurație incompletă a bibliotecii GD: lipsește funcția $1',
 'thumbnail_image-missing' => 'Fișierul următor nu poate fi găsit: $1',
+'thumbnail_image-failure-limit' => 'Recent au existat prea multe încercări nereușite ($1 sau mai multe) pentru a randa această miniatură. Încercați din nou mai târziu.',
 
 # Special:Import
 'import' => 'Importare pagini',
index 7220cd9..f5357f8 100644 (file)
@@ -1068,7 +1068,7 @@ Ovakvi argumenti se trebaju izbjegavati.",
 Molimo da provjerite usporedbu ispod da budete sigurni da to želite učiniti, a zatim spremite promjene da bi ste završili vraćanje izmjene.',
 'undo-failure' => 'Izmjene se ne mogu vratiti zbog konflikta sa izmjenama u međuvremenu.',
 'undo-norev' => 'Izmjena se ne može vratiti jer ne postoji ranija ili je obrisana.',
-'undo-summary' => 'Vraćena izmjena $1 [[Special:Contributions/$2|korisnika $2]] ([[User talk:$2|razgovor]])',
+'undo-summary' => 'Poništena izmjena $1 [[Special:Contributions/$2|korisnika $2]] ([[User talk:$2|razgovor]])',
 'undo-summary-username-hidden' => 'Poništi izmjenu $1 od skrivenog korisnika',
 
 # Account creation failure
index 894dfa2..fe2506d 100644 (file)
@@ -2906,6 +2906,7 @@ $2',
 'thumbnail_image-type' => 'Vrsta slike ni podprta',
 'thumbnail_gd-library' => 'Nepopolna konfiguracija knjižice GD: manjka funkcija $1',
 'thumbnail_image-missing' => 'Kaže, da datoteka manjka: $1',
+'thumbnail_image-failure-limit' => 'Nedavno je bilo preveč spodletelih poskusov ($1 ali več) izdelave sličice. Prosimo, poskusite znova pozneje.',
 
 # Special:Import
 'import' => 'Uvoz strani',
index 545f9d9..38131c4 100644 (file)
@@ -655,7 +655,12 @@ Imo malinamposon nga ginsalyuan an imo tigaman-panakob o umaro ka na hin bag-o n
 'passwordreset-capture-help' => 'Kun imo igtsek ini nga kahon, an email (lakip an temporaryo nga tigaman-panakob) in igpapakita ha imo labot la han ginpadangat ha gumaramit.',
 'passwordreset-email' => 'E-mail adres:',
 'passwordreset-emailtitle' => 'Mga detalye han akawnt ha {{SITENAME}}',
-'passwordreset-emailtext-ip' => '{{PLURAL:$3|Iní nga temporaryo nga tigaman-pansulod|Iní nga mga temporaryo nga tigaman-pansulod}} ma-waray bali hin {{PLURAL:$5|usa ka adlaw|$5 nga mga adlaw}}.',
+'passwordreset-emailtext-ip' => 'Mayda gumaramit (bangin hi ikaw, tikang han IP adres nga $1) nga naghangyo hin reset han imo tigaman-pansulod han {{SITENAME}} ($4). An nasunod nga gumaramit {{PLURAL:$3|nga akawnt|nga mga akawnt}} nahanungod hini nga email nga adres: 
+
+$2
+
+{{PLURAL:$3|Iní nga temporaryo nga tigaman-pansulod|Iní nga mga temporaryo nga tigaman-pansulod}} ma-waray bali hin {{PLURAL:$5|usa ka adlaw|$5 nga mga adlaw}}.
+Angay ka sumakob ngan pumílì hin bag-o nga tigaman-pansulod ha yanâ.  Kun mayda lain nga naghatag hini nga hangyo, o kun nahinumdoman mo an imo orihinal nga tigaman-pansulod, ngan nadírì ka na pagbalyo hiní, puyde mo pasagdan ini nga sumat ngan magpadayon hin paggamit han imo daan nga tigaman-pansulod.',
 'passwordreset-emailelement' => 'Agnay han gumaramit: $1
 Temporaryo nga tigaman han pagsakob: $2',
 'passwordreset-emailsent' => 'Ginpadangat an password reset email.',
@@ -673,6 +678,7 @@ Temporaryo nga tigaman han pagsakob: $2',
 'changeemail-password' => 'An imo {{SITENAME}} password:',
 'changeemail-submit' => 'Igbalyo an e-mail',
 'changeemail-cancel' => 'Pasagdi',
+'changeemail-throttled' => 'Nakadamo kada pag-log-in. Alayon paghulat hin $1 ugsa ka umutro.',
 
 # Special:ResetTokens
 'resettokens' => 'Igrest an mga token',
@@ -788,6 +794,7 @@ An pinakaurhi nga log entry han mga pinugong in ginhatag ha ubos para hit repere
 'previewnote' => "'''Hinumdumi nga pahiuna-nga-paggawas pa la ini.'''
 ¡Waray pa katipig an imo mga ginbag-o!",
 'continue-editing' => 'Pakadto han lugar hin panliwat',
+'edit_form_incomplete' => '<strong>An iba nga parte han imo pagliwat nga porma in waray umabot ha serbidor; alayon kitaa utro kun an imo mga pagliwat in aada pa ngan utroha pa.</strong>',
 'editing' => 'Ginliliwat an $1',
 'creating' => 'Ginhihimo an $1',
 'editingsection' => 'Ginliliwat an $1 (bahin)',
@@ -795,10 +802,16 @@ An pinakaurhi nga log entry han mga pinugong in ginhatag ha ubos para hit repere
 'editconflict' => 'Diri pagkakauroyon han pagliwat: $1',
 'yourtext' => 'Imo sinurat',
 'storedversion' => 'Nakahipos nga pagbag-o',
+'editingold' => '<strong>Pahimatngon: Imo ginliliwat an daan nga rebisyon hini nga pakli.</strong>
+Kun imo ini igtipig, an bisan ano nga mga pagliwat nga ginhimo tikang hini nga rebisyon in mawawara.',
 'yourdiff' => 'Mga kaibhan',
 'copyrightwarning' => "Iginpapasabot nga an ngatanan nga imo gin-amot ha {{SITENAME}} iginhatag mo ha ilarom han $2 (kitaa an $1 para han mga detalye).  Kun diri mo igkakalipay nga an imo ginsurat waray kalooy nga liliwaton ngan igpapakalat hit bisan hin-o nga it may gusto, alayon ayaw hiton igsumitir dinhi. <br />
 Nasaad ka liwat nga imo ini kalugaringon nga ginsurat, o ginkopya nimo ini tikang ha panimongto nga dominyo o kapareho nga waray-sabit nga kuruhaon.
 '''Ayaw igsumitir an mga buhat nga may ''copyright'' hin waray sarit!'''",
+'copyrightwarning2' => 'Alayon kasabot nga an ngatanan nga mga kontribusyon ha {{SITENAME}} in puydi liwaton, saliwanon, o tanggalon hin bisan hin-o nga karuyag magbuhat.
+Kun diri mo karuyag nga an imo sinurat in maliliwat la hin waray kalooy, ayaw gud igsumite dinhi.<br />
+Nasaad ka gihap nga ikaw mismo an nagsurat hini, o ginkopya mo ini ha dominyo publiko o kaparehas nga talwas nga ginkuhaan (kitaa an $1 para hin mga detalye).
+<strong>Ayaw igsumite an mga buhat nga naka-copywrite nga waray pagtugot!</strong>',
 'templatesused' => '{{PLURAL:$1|Batakan|Mga batakan}} nga gingamit dinhi nga pakli:',
 'template-protected' => '(pinaliporan)',
 'template-semiprotected' => '(katunga nga pinasaliporan)',
@@ -806,7 +819,7 @@ Nasaad ka liwat nga imo ini kalugaringon nga ginsurat, o ginkopya nimo ini tikan
 'nocreate-loggedin' => 'Diri ka gintutugotan paghimo hin mga bag-o nga pakli.',
 'sectioneditnotsupported-title' => 'Diri suportado han pagliwat han seksyon',
 'sectioneditnotsupported-text' => 'Diri suportado an pagliwat han seksyon ha dinhi nga pakli.',
-'permissionserrors' => 'Mga sayop hin mga pagtugot',
+'permissionserrors' => 'Sayop hin pagtugot',
 'permissionserrorstext' => 'Diri ka gintutugotan pagbuhat hito, mahitungod han mga nasunod nga {{PLURAL:$1|katadungan|mga katadungan}}:',
 'permissionserrorstext-withaction' => 'Waray ka permiso han $2, tungod han masunod nga {{PLURAL:$1|rason|mga rason}}:',
 'recreate-moveddeleted-warn' => "'''Pahimatngon: Naghihimo ka hin pakli nga ginpara na.'''
@@ -894,13 +907,13 @@ An mga detalye in mabibilngan ha [{{fullurl:{{#Special:Log}}/delete|page={{FULLP
 'revisiondelete' => 'Pagpara/pagtanggal han pagpara nga mga rebisyon',
 'revdelete-show-file-confirm' => 'Sigurado ka nga gusto mo makita an ginpara nga pagliwat han file "<nowiki>$1</nowiki>" tikang $2 ha $3?',
 'revdelete-show-file-submit' => 'Oo',
-'revdelete-hide-text' => 'Tagoon an rebisyon han teksto',
+'revdelete-hide-text' => 'Rebisyon nga sinurat',
 'revdelete-hide-image' => 'Tagoon an sulod han paypay',
 'revdelete-hide-name' => 'Tagoon an buhat ngan kakadtoan',
-'revdelete-hide-comment' => 'Tagoon an dalikyat nga sumat han pagliwat',
+'revdelete-hide-comment' => 'Dalikyat nga sumat hin pagliwat',
 'revdelete-radio-same' => '(ayaw balyu-e)',
-'revdelete-radio-set' => 'Oo',
-'revdelete-radio-unset' => 'Ayaw',
+'revdelete-radio-set' => 'Tinago',
+'revdelete-radio-unset' => 'Nakikit-an',
 'revdelete-log' => 'Rason:',
 'revdel-restore' => 'igliwat an nakikit-an',
 'pagehist' => 'Kaagi han pakli',
@@ -1084,7 +1097,7 @@ An imo e-mail address in diri makikit-an kun an iba nga mga gumaramit in makonta
 'prefs-i18n' => 'Internasyonalisasyon',
 'prefs-signature' => 'Pirma',
 'prefs-dateformat' => 'Batakan han petsa',
-'prefs-advancedediting' => 'Abansado nga mga pagpipilian',
+'prefs-advancedediting' => 'Mga kasahiran nga pagpipilian',
 'prefs-preview' => 'Pahiuna nga pakita',
 'prefs-advancedrc' => 'Abansado nga mga pagpipilian',
 'prefs-advancedrendering' => 'Abansado nga mga pagpipilian',
@@ -1156,7 +1169,7 @@ Diri ka gintutugotan pagliwat han mga katungod han gumaramit ha iba nga mga wiki
 'right-reupload' => 'Sapawa an mga aada nga mga paypay',
 'right-reupload-own' => 'Igsapaw an aada yana nga mga paypay nga ginkarga-pasaka nimo mismo',
 'right-upload_by_url' => 'Igkarga paigbaw an mga paypay tikang ha uska URL',
-'right-autoconfirmed' => 'Igliwat an mga semi-pinanpasaliporan nga pakli',
+'right-autoconfirmed' => 'Diri malalalbtan hin IP-nga-nahibasi nga mga rate hin paglimit',
 'right-bot' => 'Igtrato komo uska naglulugaring nga proseso',
 'right-delete' => 'Igpara an mga pakli',
 'right-bigdelete' => 'Igpara an mga pakli nga may-ada dagko nga mga kaagi',
@@ -1211,8 +1224,8 @@ Diri ka gintutugotan pagliwat han mga katungod han gumaramit ha iba nga mga wiki
 'action-suppressionlog' => 'kitaa an kanan hini pribado nga talaan',
 'action-block' => 'Pugnga ini nga gumaramit ha pagliwat',
 'action-protect' => 'igsaliwan an katupngan han pananalipod para hini nga pakli',
-'action-import' => 'ig-angbit ini nga pakli tikang ha iba nga wiki',
-'action-importupload' => 'ig-angbit ini nga pakli tikang ha uska ginkarga-pasaka nga paypay',
+'action-import' => 'ig-angbit hin mga pakli tikang ha iba nga wiki',
+'action-importupload' => 'ig-angbit hin mga pakli pakli tikang ha uska ginkarga-pasaka nga paypay',
 'action-patrol' => 'markahi an kanan iba pagliwat komo nakapatrolya',
 'action-mergehistory' => 'Igtampo an kaagi hini nga pakli',
 'action-userrights' => 'Igliwat an ngatanan nga mga katungod han gumaramit',
@@ -1232,7 +1245,7 @@ Diri ka gintutugotan pagliwat han mga katungod han gumaramit ha iba nga mga wiki
 'rclistfrom' => 'Pakit-a an mga ginbag-ohan tikang han $1',
 'rcshowhideminor' => '$1 gudti nga mga pagliwat',
 'rcshowhidebots' => '$1 mga bot',
-'rcshowhideliu' => '$1 ka rehistrado nga gumaramit',
+'rcshowhideliu' => '$1 an mga rehistrado nga gumaramit',
 'rcshowhideanons' => '$1 waray nagpakilala nga mga gumaramit',
 'rcshowhidepatr' => '$1 mga pinatrolya nga mga paliwat',
 'rcshowhidemine' => '$1 akon mga ginliwat',
@@ -1707,9 +1720,11 @@ Kitaa an $2 para hin talaan han mga gibag-ohi nga mga ginpamara.',
 'deleteotherreason' => 'Lain/dugang nga katadungan:',
 'deletereasonotherlist' => 'Lain nga katadungan',
 'deletereason-dropdown' => "*Agsob nga rason hin pagpara
-** Tugon han manunurat
+** Spam
+** Bandalismo
 ** Pagtalapas ha katungod hin pagtatag-iya (''copyright'')
-** Bandalismo",
+** Tugon han manunurat
+** Utod nga redirek",
 'delete-edit-reasonlist' => 'Igliwat an mga rason han pagpara',
 
 # Rollback
@@ -2059,12 +2074,12 @@ Makikit-an nimo an ginkuhaaan',
 'pageinfo-display-title' => 'Iglatag an titulo',
 'pageinfo-length' => 'Kahilaba han pakli (ha mga byte)',
 'pageinfo-article-id' => 'ID han pakli',
-'pageinfo-robot-policy' => 'Pamilnga an kahimtang han makina',
-'pageinfo-robot-index' => 'Matutudlok',
-'pageinfo-robot-noindex' => 'Diri matutudlok',
+'pageinfo-robot-policy' => 'Pag-index hin mga robot',
+'pageinfo-robot-index' => 'Gintutugot',
+'pageinfo-robot-noindex' => 'Dírì gintutugot',
 'pageinfo-views' => 'Ihap han mga naglantaw',
 'pageinfo-watchers' => 'Ihap han nangingita hin pakli',
-'pageinfo-redirects-name' => 'Nairedirekta ha dinhi nga pakli',
+'pageinfo-redirects-name' => 'Ihap hin mga redirek ngani nga pakli',
 'pageinfo-subpages-name' => 'Mga bahinpakli hin nga pakli',
 'pageinfo-subpages-value' => '$1 ($2 {{PLURAL:$2|redirekta|mga redirekta}}; $3 {{PLURAL:$3|diri redirekta|mga diri redirekta}})',
 'pageinfo-firstuser' => 'Naghimo han pakli',
@@ -2217,7 +2232,7 @@ An iba in daan nakatago.
 'exif-cameraownername' => 'Tag-iya han kamera',
 'exif-usageterms' => 'Mga termino hit paggamit',
 
-'exif-copyrighted-false' => 'Dominyo panpubliko',
+'exif-copyrighted-false' => 'Status hin katungod-hin-panag-iya waray mahabutang',
 
 'exif-unknowndate' => 'Waray kasabti an petsa',
 
@@ -2401,7 +2416,7 @@ An iba in daan nakatago.
 'version-hooks' => 'Mga kawil',
 'version-hook-name' => 'Ngaran han kawil',
 'version-version' => '(Bersion $1)',
-'version-license' => 'Lisensya',
+'version-license' => 'MediaWiki nga Lisensya',
 'version-poweredby-credits' => "Ini nga wiki in pinapaandar han '''[https://www.mediawiki.org/ MediaWiki]''', copyright © 2001-$1 $2.",
 'version-poweredby-others' => 'mga iba',
 'version-software-product' => 'Produkto',
@@ -2473,10 +2488,10 @@ An iba in daan nakatago.
 'revdelete-content-hid' => 'sulod nakatago',
 'revdelete-summary-hid' => 'nakatago an dalikyat nga sumat han pagliwat',
 'revdelete-uname-hid' => 'nakatago an agnay-hit-gumaramit',
-'logentry-newusers-newusers' => '$1 in naghimo hin gumaramit nga akawnt',
-'logentry-newusers-create' => '$1 in naghimo hin gumaramit nga akawnt',
-'logentry-newusers-create2' => '$1 in naghimo hin gumaramit nga akawnt $3',
-'logentry-newusers-autocreate' => 'An akawnt nga $1 in lugaring nga nahimo',
+'logentry-newusers-newusers' => 'An gumaramit nga akawnt nga $1 {{GENDER:$2|ginhimo}}',
+'logentry-newusers-create' => 'An gumaramit nga akawnt nga $1 {{GENDER:$2|ginhimo}}',
+'logentry-newusers-create2' => 'An gumaramit nga akawnt nga $3 {{GENDER:$2|ginhimo}} ni $1',
+'logentry-newusers-autocreate' => 'An gumaramit nga akawnt nga $1 in lugaring nga {{GENDER:$2|ginhimo}}',
 'rightsnone' => '(waray)',
 
 # Feedback
index b74b032..f1cd2f8 100644 (file)
                                "classes": [
                                        "mw.page*"
                                ]
+                       },
+                       {
+                               "name": "Interfaces",
+                               "classes": [
+                                       "mw.Feedback"
+                               ]
                        }
                ]
        },
index dae4e43..216c19b 100644 (file)
@@ -12,6 +12,7 @@
                "./external.js",
                "../../resources/mediawiki/mediawiki.js",
                "../../resources/mediawiki/mediawiki.htmlform.js",
+               "../../resources/mediawiki/mediawiki.feedback.js",
                "../../resources/mediawiki/mediawiki.log.js",
                "../../resources/mediawiki/mediawiki.util.js",
                "../../resources/mediawiki/mediawiki.Title.js",
index d692e2b..c4866a5 100644 (file)
@@ -181,6 +181,7 @@ $wgIgnoredMessages = array(
        'brokenredirects-summary',
        'deadendpages-summary',
        'protectedpages-summary',
+       'protectedpages-unknown-reason',
        'disambiguations-summary',
        'pageswithprop-summary',
        'doubleredirects-summary',
index 6e6c3ed..935dae7 100644 (file)
@@ -1816,6 +1816,15 @@ $wgMessageStructure = array(
                'protectedpages-cascade',
                'protectedpages-noredirect',
                'protectedpagesempty',
+               'protectedpages-timestamp',
+               'protectedpages-page',
+               'protectedpages-expiry',
+               'protectedpages-performer',
+               'protectedpages-params',
+               'protectedpages-reason',
+               'protectedpages-unknown-timestamp',
+               'protectedpages-unknown-performer',
+               'protectedpages-unknown-reason',
                'protectedtitles',
                'protectedtitles-summary',
                'protectedtitlesempty',
index 3ae330b..986fd59 100644 (file)
@@ -339,6 +339,9 @@ return array(
                'scripts' => 'resources/jquery/jquery.textSelection.js',
                'dependencies' => 'jquery.client',
        ),
+       'jquery.throttle-debounce' => array(
+               'scripts' => 'resources/jquery/jquery.ba-throttle-debounce.js',
+       ),
        'jquery.validate' => array(
                'scripts' => 'resources/jquery/jquery.validate.js',
        ),
@@ -1278,10 +1281,10 @@ return array(
 
        'oojs-ui' => array(
                'scripts' => array(
-                       'resources/oojs/oojs-ui.js',
+                       'resources/oojs-ui/oojs-ui.js',
                ),
                'styles' => array(
-                       'resources/oojs/oojs-ui.svg.css',
+                       'resources/oojs-ui/oojs-ui.svg.css',
                ),
                'messages' => array(
                        'ooui-dialog-action-close',
diff --git a/resources/jquery/jquery.ba-throttle-debounce.js b/resources/jquery/jquery.ba-throttle-debounce.js
new file mode 100644 (file)
index 0000000..fa30bdf
--- /dev/null
@@ -0,0 +1,252 @@
+/*!
+ * jQuery throttle / debounce - v1.1 - 3/7/2010
+ * http://benalman.com/projects/jquery-throttle-debounce-plugin/
+ * 
+ * Copyright (c) 2010 "Cowboy" Ben Alman
+ * Dual licensed under the MIT and GPL licenses.
+ * http://benalman.com/about/license/
+ */
+
+// Script: jQuery throttle / debounce: Sometimes, less is more!
+//
+// *Version: 1.1, Last updated: 3/7/2010*
+// 
+// Project Home - http://benalman.com/projects/jquery-throttle-debounce-plugin/
+// GitHub       - http://github.com/cowboy/jquery-throttle-debounce/
+// Source       - http://github.com/cowboy/jquery-throttle-debounce/raw/master/jquery.ba-throttle-debounce.js
+// (Minified)   - http://github.com/cowboy/jquery-throttle-debounce/raw/master/jquery.ba-throttle-debounce.min.js (0.7kb)
+// 
+// About: License
+// 
+// Copyright (c) 2010 "Cowboy" Ben Alman,
+// Dual licensed under the MIT and GPL licenses.
+// http://benalman.com/about/license/
+// 
+// About: Examples
+// 
+// These working examples, complete with fully commented code, illustrate a few
+// ways in which this plugin can be used.
+// 
+// Throttle - http://benalman.com/code/projects/jquery-throttle-debounce/examples/throttle/
+// Debounce - http://benalman.com/code/projects/jquery-throttle-debounce/examples/debounce/
+// 
+// About: Support and Testing
+// 
+// Information about what version or versions of jQuery this plugin has been
+// tested with, what browsers it has been tested in, and where the unit tests
+// reside (so you can test it yourself).
+// 
+// jQuery Versions - none, 1.3.2, 1.4.2
+// Browsers Tested - Internet Explorer 6-8, Firefox 2-3.6, Safari 3-4, Chrome 4-5, Opera 9.6-10.1.
+// Unit Tests      - http://benalman.com/code/projects/jquery-throttle-debounce/unit/
+// 
+// About: Release History
+// 
+// 1.1 - (3/7/2010) Fixed a bug in <jQuery.throttle> where trailing callbacks
+//       executed later than they should. Reworked a fair amount of internal
+//       logic as well.
+// 1.0 - (3/6/2010) Initial release as a stand-alone project. Migrated over
+//       from jquery-misc repo v0.4 to jquery-throttle repo v1.0, added the
+//       no_trailing throttle parameter and debounce functionality.
+// 
+// Topic: Note for non-jQuery users
+// 
+// jQuery isn't actually required for this plugin, because nothing internal
+// uses any jQuery methods or properties. jQuery is just used as a namespace
+// under which these methods can exist.
+// 
+// Since jQuery isn't actually required for this plugin, if jQuery doesn't exist
+// when this plugin is loaded, the method described below will be created in
+// the `Cowboy` namespace. Usage will be exactly the same, but instead of
+// $.method() or jQuery.method(), you'll need to use Cowboy.method().
+
+(function(window,undefined){
+  '$:nomunge'; // Used by YUI compressor.
+  
+  // Since jQuery really isn't required for this plugin, use `jQuery` as the
+  // namespace only if it already exists, otherwise use the `Cowboy` namespace,
+  // creating it if necessary.
+  var $ = window.jQuery || window.Cowboy || ( window.Cowboy = {} ),
+    
+    // Internal method reference.
+    jq_throttle;
+  
+  // Method: jQuery.throttle
+  // 
+  // Throttle execution of a function. Especially useful for rate limiting
+  // execution of handlers on events like resize and scroll. If you want to
+  // rate-limit execution of a function to a single time, see the
+  // <jQuery.debounce> method.
+  // 
+  // In this visualization, | is a throttled-function call and X is the actual
+  // callback execution:
+  // 
+  // > Throttled with `no_trailing` specified as false or unspecified:
+  // > ||||||||||||||||||||||||| (pause) |||||||||||||||||||||||||
+  // > X    X    X    X    X    X        X    X    X    X    X    X
+  // > 
+  // > Throttled with `no_trailing` specified as true:
+  // > ||||||||||||||||||||||||| (pause) |||||||||||||||||||||||||
+  // > X    X    X    X    X             X    X    X    X    X
+  // 
+  // Usage:
+  // 
+  // > var throttled = jQuery.throttle( delay, [ no_trailing, ] callback );
+  // > 
+  // > jQuery('selector').bind( 'someevent', throttled );
+  // > jQuery('selector').unbind( 'someevent', throttled );
+  // 
+  // This also works in jQuery 1.4+:
+  // 
+  // > jQuery('selector').bind( 'someevent', jQuery.throttle( delay, [ no_trailing, ] callback ) );
+  // > jQuery('selector').unbind( 'someevent', callback );
+  // 
+  // Arguments:
+  // 
+  //  delay - (Number) A zero-or-greater delay in milliseconds. For event
+  //    callbacks, values around 100 or 250 (or even higher) are most useful.
+  //  no_trailing - (Boolean) Optional, defaults to false. If no_trailing is
+  //    true, callback will only execute every `delay` milliseconds while the
+  //    throttled-function is being called. If no_trailing is false or
+  //    unspecified, callback will be executed one final time after the last
+  //    throttled-function call. (After the throttled-function has not been
+  //    called for `delay` milliseconds, the internal counter is reset)
+  //  callback - (Function) A function to be executed after delay milliseconds.
+  //    The `this` context and all arguments are passed through, as-is, to
+  //    `callback` when the throttled-function is executed.
+  // 
+  // Returns:
+  // 
+  //  (Function) A new, throttled, function.
+  
+  $.throttle = jq_throttle = function( delay, no_trailing, callback, debounce_mode ) {
+    // After wrapper has stopped being called, this timeout ensures that
+    // `callback` is executed at the proper times in `throttle` and `end`
+    // debounce modes.
+    var timeout_id,
+      
+      // Keep track of the last time `callback` was executed.
+      last_exec = 0;
+    
+    // `no_trailing` defaults to falsy.
+    if ( typeof no_trailing !== 'boolean' ) {
+      debounce_mode = callback;
+      callback = no_trailing;
+      no_trailing = undefined;
+    }
+    
+    // The `wrapper` function encapsulates all of the throttling / debouncing
+    // functionality and when executed will limit the rate at which `callback`
+    // is executed.
+    function wrapper() {
+      var that = this,
+        elapsed = +new Date() - last_exec,
+        args = arguments;
+      
+      // Execute `callback` and update the `last_exec` timestamp.
+      function exec() {
+        last_exec = +new Date();
+        callback.apply( that, args );
+      };
+      
+      // If `debounce_mode` is true (at_begin) this is used to clear the flag
+      // to allow future `callback` executions.
+      function clear() {
+        timeout_id = undefined;
+      };
+      
+      if ( debounce_mode && !timeout_id ) {
+        // Since `wrapper` is being called for the first time and
+        // `debounce_mode` is true (at_begin), execute `callback`.
+        exec();
+      }
+      
+      // Clear any existing timeout.
+      timeout_id && clearTimeout( timeout_id );
+      
+      if ( debounce_mode === undefined && elapsed > delay ) {
+        // In throttle mode, if `delay` time has been exceeded, execute
+        // `callback`.
+        exec();
+        
+      } else if ( no_trailing !== true ) {
+        // In trailing throttle mode, since `delay` time has not been
+        // exceeded, schedule `callback` to execute `delay` ms after most
+        // recent execution.
+        // 
+        // If `debounce_mode` is true (at_begin), schedule `clear` to execute
+        // after `delay` ms.
+        // 
+        // If `debounce_mode` is false (at end), schedule `callback` to
+        // execute after `delay` ms.
+        timeout_id = setTimeout( debounce_mode ? clear : exec, debounce_mode === undefined ? delay - elapsed : delay );
+      }
+    };
+    
+    // Set the guid of `wrapper` function to the same of original callback, so
+    // it can be removed in jQuery 1.4+ .unbind or .die by using the original
+    // callback as a reference.
+    if ( $.guid ) {
+      wrapper.guid = callback.guid = callback.guid || $.guid++;
+    }
+    
+    // Return the wrapper function.
+    return wrapper;
+  };
+  
+  // Method: jQuery.debounce
+  // 
+  // Debounce execution of a function. Debouncing, unlike throttling,
+  // guarantees that a function is only executed a single time, either at the
+  // very beginning of a series of calls, or at the very end. If you want to
+  // simply rate-limit execution of a function, see the <jQuery.throttle>
+  // method.
+  // 
+  // In this visualization, | is a debounced-function call and X is the actual
+  // callback execution:
+  // 
+  // > Debounced with `at_begin` specified as false or unspecified:
+  // > ||||||||||||||||||||||||| (pause) |||||||||||||||||||||||||
+  // >                          X                                 X
+  // > 
+  // > Debounced with `at_begin` specified as true:
+  // > ||||||||||||||||||||||||| (pause) |||||||||||||||||||||||||
+  // > X                                 X
+  // 
+  // Usage:
+  // 
+  // > var debounced = jQuery.debounce( delay, [ at_begin, ] callback );
+  // > 
+  // > jQuery('selector').bind( 'someevent', debounced );
+  // > jQuery('selector').unbind( 'someevent', debounced );
+  // 
+  // This also works in jQuery 1.4+:
+  // 
+  // > jQuery('selector').bind( 'someevent', jQuery.debounce( delay, [ at_begin, ] callback ) );
+  // > jQuery('selector').unbind( 'someevent', callback );
+  // 
+  // Arguments:
+  // 
+  //  delay - (Number) A zero-or-greater delay in milliseconds. For event
+  //    callbacks, values around 100 or 250 (or even higher) are most useful.
+  //  at_begin - (Boolean) Optional, defaults to false. If at_begin is false or
+  //    unspecified, callback will only be executed `delay` milliseconds after
+  //    the last debounced-function call. If at_begin is true, callback will be
+  //    executed only at the first debounced-function call. (After the
+  //    throttled-function has not been called for `delay` milliseconds, the
+  //    internal counter is reset)
+  //  callback - (Function) A function to be executed after delay milliseconds.
+  //    The `this` context and all arguments are passed through, as-is, to
+  //    `callback` when the debounced-function is executed.
+  // 
+  // Returns:
+  // 
+  //  (Function) A new, debounced, function.
+  
+  $.debounce = function( delay, at_begin, callback ) {
+    return callback === undefined
+      ? jq_throttle( delay, at_begin, false )
+      : jq_throttle( delay, callback, at_begin !== false );
+  };
+  
+})(this);
index cdc6767..6012d93 100644 (file)
                                        } );
                                } )
                                // AJAX success just means "200 OK" response, also check API error codes
-                               .done( function ( result ) {
+                               .done( function ( result, textStatus, jqXHR ) {
                                        if ( result === undefined || result === null || result === '' ) {
                                                apiDeferred.reject( 'ok-but-empty',
                                                        'OK response but empty result (check HTTP headers?)'
                                                var code = result.error.code === undefined ? 'unknown' : result.error.code;
                                                apiDeferred.reject( code, result );
                                        } else {
-                                               apiDeferred.resolve( result );
+                                               apiDeferred.resolve( result, jqXHR );
                                        }
                                } );
 
index b02e8f2..ee4fc06 100644 (file)
@@ -264,6 +264,18 @@ td.mw-statistics-numbers {
        text-align: right;
 }
 
+/**** Special:ProtectedPages ****/
+table.mw-protectedpages span.mw-usertoollinks,
+span.mw-protectedpages-length,
+span.mw-protectedpages-actions {
+       white-space: nowrap;
+       font-size: 90%;
+}
+span.mw-protectedpages-unknown {
+       color: grey;
+       font-size: 90%;
+}
+
 /**** Special:UserRights ****/
 .mw-userrights-disabled {
        color: #888;
index 9de69b2..a498484 100644 (file)
@@ -1,41 +1,44 @@
-/**
+/*!
  * mediawiki.feedback
  *
  * @author Ryan Kaldari, 2010
  * @author Neil Kandalgaonkar, 2010-11
  * @since 1.19
- *
- * This is a way of getting simple feedback from users. It's useful
- * for testing new features -- users can give you feedback without
- * the difficulty of opening a whole new talk page. For this reason,
- * it also tends to collect a wider range of both positive and negative
- * comments. However you do need to tend to the feedback page. It will
- * get long relatively quickly, and you often get multiple messages
- * reporting the same issue.
- *
- * It takes the form of thing on your page which, when clicked, opens a small
- * dialog box. Submitting that dialog box appends its contents to a
- * wiki page that you specify, as a new section.
- *
- * Not compatible with LiquidThreads.
- *
- * Minimal example in how to use it:
- *
- *    var feedback = new mw.Feedback();
- *    $( '#myButton' ).click( function () { feedback.launch(); } );
- *
- * You can also launch the feedback form with a prefilled subject and body.
- * See the docs for the launch() method.
  */
 ( function ( mw, $ ) {
        /**
-        * Thingy for collecting user feedback on a wiki page
-        * @param {Array} options -- optional, all properties optional.
-        *  api: {mw.Api} if omitted, will just create a standard API
-        *  title: {mw.Title} the title of the page where you collect feedback. Defaults to "Feedback".
-        *  dialogTitleMessageKey: {String} message key for the title of the dialog box
-        *  bugsLink: {mw.Uri|String} url where bugs can be posted
-        *  bugsListLink: {mw.Uri|String} url where bugs can be listed
+        * This is a way of getting simple feedback from users. It's useful
+        * for testing new features -- users can give you feedback without
+        * the difficulty of opening a whole new talk page. For this reason,
+        * it also tends to collect a wider range of both positive and negative
+        * comments. However you do need to tend to the feedback page. It will
+        * get long relatively quickly, and you often get multiple messages
+        * reporting the same issue.
+        *
+        * It takes the form of thing on your page which, when clicked, opens a small
+        * dialog box. Submitting that dialog box appends its contents to a
+        * wiki page that you specify, as a new section.
+        *
+        * Not compatible with LiquidThreads.
+        *
+        * Minimal example in how to use it:
+        *
+        *     var feedback = new mw.Feedback();
+        *     $( '#myButton' ).click( function () { feedback.launch(); } );
+        *
+        * You can also launch the feedback form with a prefilled subject and body.
+        * See the docs for the #launch() method.
+        *
+        * @param {Object} [options]
+        * @param {mw.Api} [options.api] if omitted, will just create a standard API
+        * @param {mw.Title} [options.title="Feedback"] The title of the page where you collect
+        * feedback.
+        * @param {string} [options.dialogTitleMessageKey="feedback-submit"] Message key for the
+        * title of the dialog box
+        * @param {string} [options.bugsLink="//bugzilla.wikimedia.org/enter_bug.cgi"] URL where
+        * bugs can be posted
+        * @param {mw.Uri|string} [options.bugsListLink="//bugzilla.wikimedia.org/query.cgi"]
+        * URL where bugs can be listed
         */
        mw.Feedback = function ( options ) {
                if ( options === undefined ) {
@@ -67,6 +70,9 @@
        };
 
        mw.Feedback.prototype = {
+               /**
+                * Sets up interface
+                */
                setup: function () {
                        var $feedbackPageLink,
                                $bugNoteLink,
 
                },
 
+               /**
+                * Displays a section of the dialog.
+                *
+                * @param {"form"|"bugs"|"submitting"|"thanks"|"error"} s
+                * The section of the dialog to show.
+                */
                display: function ( s ) {
                        this.$dialog.dialog( { buttons:{} } ); // hide the buttons
                        this.$dialog.find( '.feedback-mode' ).hide(); // hide everything
                        this.$dialog.find( '.feedback-' + s ).show(); // show the desired div
                },
 
+               /**
+                * Display the submitting section.
+                */
                displaySubmitting: function () {
                        this.display( 'submitting' );
                },
 
+               /**
+                * Display the bugs section.
+                */
                displayBugs: function () {
                        var fb = this,
                                bugsButtons = {};
                        } );
                },
 
+               /**
+                * Display the thanks section.
+                */
                displayThanks: function () {
                        var fb = this,
                                closeButton = {};
 
                /**
                 * Display the feedback form
-                * @param {Object} optional prefilled contents for the feedback form. Object with properties:
-                *  subject: {String}
-                *      message: {String}
+                * @param {Object} [contents] Prefilled contents for the feedback form.
+                * @param {string} [contents.subject] The subject of the feedback
+                * @param {string} [contents.message] The content of the feedback
                 */
                displayForm: function ( contents ) {
                        var fb = this,
                        this.$dialog.dialog( { buttons: formButtons } ); // put the buttons back
                },
 
+               /**
+                * Display an error on the form.
+                *
+                * @param {string} message Should be a valid message key.
+                */
                displayError: function ( message ) {
                        var fb = this,
                                closeButton = {};
                        this.$dialog.dialog( { buttons: closeButton } );
                },
 
+               /**
+                * Close the feedback form.
+                */
                cancel: function () {
                        this.$dialog.dialog( 'close' );
                },
 
+               /**
+                * Submit the feedback form.
+                */
                submit: function () {
                        var subject, message,
                                fb = this;
 
                /**
                 * Modify the display form, and then open it, focusing interface on the subject.
-                * @param {Object} optional prefilled contents for the feedback form. Object with properties:
-                *                                              subject: {String}
-                *                                              message: {String}
+                * @param {Object} [contents] Prefilled contents for the feedback form.
+                * @param {string} [contents.subject] The subject of the feedback
+                * @param {string} [contents.message] The content of the feedback
                 */
                launch: function ( contents ) {
                        this.displayForm( contents );
index 5f20ee4..d7d90f4 100644 (file)
                                ] );
                                return result === null ? null : [ result[0], result[2] ];
                        }
+                       function templateWithOutFirstParameter() {
+                               var result = sequence( [
+                                       templateName,
+                                       colon
+                               ] );
+                               return result === null ? null : [ result[0], '' ];
+                       }
                        colon = makeStringParser( ':' );
                        templateContents = choice( [
                                function () {
                                        var res = sequence( [
                                                // templates can have placeholders for dynamic replacement eg: {{PLURAL:$1|one car|$1 cars}}
                                                // or no placeholders eg: {{GRAMMAR:genitive|{{SITENAME}}}
-                                               choice( [ templateWithReplacement, templateWithOutReplacement ] ),
+                                               choice( [ templateWithReplacement, templateWithOutReplacement, templateWithOutFirstParameter ] ),
                                                nOrMore( 0, templateParam )
                                        ] );
                                        return res === null ? null : res[0].concat( res[1] );
 
                /**
                 * Transform parsed structure according to gender.
-                * Usage {{gender:[ gender | mw.user object ] | masculine form|feminine form|neutral form}}.
-                * The first node is either a string, which can be "male" or "female",
-                * or a User object (not a username).
                 *
-                * @param {Array} nodes List of nodes, [ {string|mw.User}, {string}, {string}, {string} ]
-                * @return {string} selected gender form according to current language
+                * Usage: {{gender:[ mw.user object | '' | 'male' | 'female' | 'unknown' ] | masculine form | feminine form | neutral form}}.
+                *
+                * The first node must be one of:
+                * - the mw.user object (or a compatible one)
+                * - an empty string - indicating the current user, same effect as passing the mw.user object
+                * - a gender string ('male', 'female' or 'unknown')
+                *
+                * @param {Array} nodes List of nodes, [ {string|mw.user}, {string}, {string}, {string} ]
+                * @return {string} Selected gender form according to current language
                 */
                gender: function ( nodes ) {
-                       var gender, forms;
+                       var gender,
+                               maybeUser = nodes[0],
+                               forms = nodes.slice( 1 );
 
-                       if  ( nodes[0] && nodes[0].options instanceof mw.Map ) {
-                               gender = nodes[0].options.get( 'gender' );
-                       } else {
-                               gender = nodes[0];
+                       if ( maybeUser === '' ) {
+                               maybeUser = mw.user;
                        }
 
-                       forms = nodes.slice( 1 );
+                       // If we are passed a mw.user-like object, check their gender.
+                       // Otherwise, assume the gender string itself was passed .
+                       if ( maybeUser && maybeUser.options instanceof mw.Map ) {
+                               gender = maybeUser.options.get( 'gender' );
+                       } else {
+                               gender = maybeUser;
+                       }
 
                        return this.language.gender( gender, forms );
                },
index 7879d6f..716c326 100644 (file)
@@ -23,6 +23,7 @@ template
 templateContents
   = twr:templateWithReplacement p:templateParam* { return twr.concat(p) }
   / twr:templateWithOutReplacement p:templateParam* { return twr.concat(p) }
+  / twr:templateWithOutFirstParameter p:templateParam* { return twr.concat(p) }
   / t:templateName p:templateParam* { return p.length ? [ t, p ] : [ t ] }
 
 templateWithReplacement
@@ -31,6 +32,9 @@ templateWithReplacement
 templateWithOutReplacement
   = t:templateName ":" p:paramExpression { return [ t, p ] }
 
+templateWithOutFirstParameter
+  = t:templateName ":" { return [ t, "" ] }
+
 templateParam
   = "|" e:paramExpression* { return e.length > 1 ? [ "CONCAT" ].concat(e) : e[0]; }
 
diff --git a/resources/oojs-ui/i18n/ace.json b/resources/oojs-ui/i18n/ace.json
new file mode 100644 (file)
index 0000000..554ae57
--- /dev/null
@@ -0,0 +1,11 @@
+{
+    "@metadata": {
+        "authors": [
+            "Si Gam Acèh"
+        ]
+    },
+    "ooui-dialog-action-close": "Tôp",
+    "ooui-outline-control-move-down": "Pinah item u yup",
+    "ooui-outline-control-move-up": "Pinah item u ateuëh",
+    "ooui-toolbar-more": "Lom"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/af.json b/resources/oojs-ui/i18n/af.json
new file mode 100644 (file)
index 0000000..a622f89
--- /dev/null
@@ -0,0 +1,10 @@
+{
+    "@metadata": {
+        "authors": [
+            "Naudefj"
+        ]
+    },
+    "ooui-dialog-action-close": "Sluit",
+    "ooui-outline-control-move-down": "Skuif item af",
+    "ooui-outline-control-move-up": "Skuif item op"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/am.json b/resources/oojs-ui/i18n/am.json
new file mode 100644 (file)
index 0000000..61e4ff6
--- /dev/null
@@ -0,0 +1,8 @@
+{
+    "@metadata": {
+        "authors": [
+            "Elfalem"
+        ]
+    },
+    "ooui-dialog-action-close": "ለመዝጋት"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/ar.json b/resources/oojs-ui/i18n/ar.json
new file mode 100644 (file)
index 0000000..65e1364
--- /dev/null
@@ -0,0 +1,18 @@
+{
+    "@metadata": {
+        "authors": [
+            "Ciphers",
+            "Claw eg",
+            "Elfalem",
+            "Jdforrester",
+            "Mido",
+            "OsamaK",
+            "زكريا",
+            "مشعل الحربي"
+        ]
+    },
+    "ooui-dialog-action-close": "أغلق",
+    "ooui-outline-control-move-down": "انقل العنصر للأسفل",
+    "ooui-outline-control-move-up": "انقل العنصر للأعلى",
+    "ooui-toolbar-more": "مزيد"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/arc.json b/resources/oojs-ui/i18n/arc.json
new file mode 100644 (file)
index 0000000..0f9e75d
--- /dev/null
@@ -0,0 +1,8 @@
+{
+    "@metadata": {
+        "authors": [
+            "Basharh"
+        ]
+    },
+    "ooui-dialog-action-close": "ܣܟܘܪ"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/ast.json b/resources/oojs-ui/i18n/ast.json
new file mode 100644 (file)
index 0000000..959ea23
--- /dev/null
@@ -0,0 +1,13 @@
+{
+    "@metadata": {
+        "authors": [
+            "Basharh",
+            "Bishnu Saikia",
+            "Xuacu"
+        ]
+    },
+    "ooui-dialog-action-close": "Zarrar",
+    "ooui-outline-control-move-down": "Mover abaxo l'elementu",
+    "ooui-outline-control-move-up": "Mover arriba l'elementu",
+    "ooui-toolbar-more": "Más"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/az.json b/resources/oojs-ui/i18n/az.json
new file mode 100644 (file)
index 0000000..8bfcf88
--- /dev/null
@@ -0,0 +1,12 @@
+{
+    "@metadata": {
+        "authors": [
+            "Cekli829",
+            "Interfase",
+            "Jduranboger"
+        ]
+    },
+    "ooui-dialog-action-close": "Bağla",
+    "ooui-outline-control-move-down": "Bəndi aşağı apar",
+    "ooui-outline-control-move-up": "Bəndi yuxarı apar"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/ba.json b/resources/oojs-ui/i18n/ba.json
new file mode 100644 (file)
index 0000000..4af0114
--- /dev/null
@@ -0,0 +1,15 @@
+{
+    "@metadata": {
+        "authors": [
+            "AiseluRB",
+            "Amire80",
+            "Assele",
+            "Haqmar",
+            "Sagan",
+            "Рустам Нурыев"
+        ]
+    },
+    "ooui-dialog-action-close": "Ябырға",
+    "ooui-outline-control-move-down": "Аҫҡа күсерергә",
+    "ooui-outline-control-move-up": "Өҫкә күсерергә"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/bcl.json b/resources/oojs-ui/i18n/bcl.json
new file mode 100644 (file)
index 0000000..aff451e
--- /dev/null
@@ -0,0 +1,12 @@
+{
+    "@metadata": {
+        "authors": [
+            "Geopoet",
+            "Sky Harbor"
+        ]
+    },
+    "ooui-dialog-action-close": "Seraduhon",
+    "ooui-outline-control-move-down": "Balyuhon an aytem paibaba",
+    "ooui-outline-control-move-up": "Balyuhon an aytem paitaas",
+    "ooui-toolbar-more": "Kadugangan"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/be-tarask.json b/resources/oojs-ui/i18n/be-tarask.json
new file mode 100644 (file)
index 0000000..5922f61
--- /dev/null
@@ -0,0 +1,14 @@
+{
+    "@metadata": {
+        "authors": [
+            "EugeneZelenko",
+            "Wizardist",
+            "Чаховіч Уладзіслаў",
+            "Zedlik"
+        ]
+    },
+    "ooui-dialog-action-close": "Закрыць",
+    "ooui-outline-control-move-down": "Перасунуць ніжэй",
+    "ooui-outline-control-move-up": "Перасунуць вышэй",
+    "ooui-toolbar-more": "Болей"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/be.json b/resources/oojs-ui/i18n/be.json
new file mode 100644 (file)
index 0000000..3058ab8
--- /dev/null
@@ -0,0 +1,8 @@
+{
+    "@metadata": {
+        "authors": [
+            "Чаховіч Уладзіслаў"
+        ]
+    },
+    "ooui-dialog-action-close": "Закрыць"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/bg.json b/resources/oojs-ui/i18n/bg.json
new file mode 100644 (file)
index 0000000..67e664b
--- /dev/null
@@ -0,0 +1,11 @@
+{
+    "@metadata": {
+        "authors": [
+            "DCLXVI",
+            "Hristofor.mirchev",
+            "පසිඳු කාවින්ද"
+        ]
+    },
+    "ooui-dialog-action-close": "Затваряне",
+    "ooui-toolbar-more": "Още"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/bn.json b/resources/oojs-ui/i18n/bn.json
new file mode 100644 (file)
index 0000000..c321ab1
--- /dev/null
@@ -0,0 +1,16 @@
+{
+    "@metadata": {
+        "authors": [
+            "Aftab1995",
+            "Bellayet",
+            "Jayantanth",
+            "Nasir8891",
+            "Runab",
+            "Sayak Sarkar"
+        ]
+    },
+    "ooui-dialog-action-close": "বন্ধ",
+    "ooui-outline-control-move-down": "আইটেম নিচে স্থানান্তর",
+    "ooui-outline-control-move-up": "আইটেম উপরে স্থানান্তর",
+    "ooui-toolbar-more": "আরও"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/br.json b/resources/oojs-ui/i18n/br.json
new file mode 100644 (file)
index 0000000..38eb9e8
--- /dev/null
@@ -0,0 +1,12 @@
+{
+    "@metadata": {
+        "authors": [
+            "Fohanno",
+            "Fulup",
+            "Y-M D"
+        ]
+    },
+    "ooui-dialog-action-close": "Serriñ",
+    "ooui-outline-control-move-down": "Lakaat an elfenn da ziskenn",
+    "ooui-outline-control-move-up": "Lakaat an elfenn da bignat"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/bs.json b/resources/oojs-ui/i18n/bs.json
new file mode 100644 (file)
index 0000000..7449f07
--- /dev/null
@@ -0,0 +1,11 @@
+{
+    "@metadata": {
+        "authors": [
+            "DzWiki"
+        ]
+    },
+    "ooui-dialog-action-close": "Zatvori",
+    "ooui-outline-control-move-down": "Premjesti stavku dole",
+    "ooui-outline-control-move-up": "Premjesti stavku gore",
+    "ooui-toolbar-more": "Više"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/ca.json b/resources/oojs-ui/i18n/ca.json
new file mode 100644 (file)
index 0000000..61bb1f6
--- /dev/null
@@ -0,0 +1,17 @@
+{
+    "@metadata": {
+        "authors": [
+            "Alvaro Vidal-Abarca",
+            "Amire80",
+            "Arnaugir",
+            "Pginer",
+            "QuimGil",
+            "SMP",
+            "Vriullop"
+        ]
+    },
+    "ooui-dialog-action-close": "Tanca",
+    "ooui-outline-control-move-down": "Baixa element",
+    "ooui-outline-control-move-up": "Puja element",
+    "ooui-toolbar-more": "Més"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/ce.json b/resources/oojs-ui/i18n/ce.json
new file mode 100644 (file)
index 0000000..1e145ea
--- /dev/null
@@ -0,0 +1,12 @@
+{
+    "@metadata": {
+        "authors": [
+            "Amire80",
+            "Умар"
+        ]
+    },
+    "ooui-dialog-action-close": "ДӀачӀагӀа",
+    "ooui-outline-control-move-down": "Лаха яккха элемент",
+    "ooui-outline-control-move-up": "Лаккха яккха элемент",
+    "ooui-toolbar-more": "Кхин тӀе"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/ckb.json b/resources/oojs-ui/i18n/ckb.json
new file mode 100644 (file)
index 0000000..839f4a8
--- /dev/null
@@ -0,0 +1,9 @@
+{
+    "@metadata": {
+        "authors": [
+            "Calak",
+            "Muhammed taha"
+        ]
+    },
+    "ooui-dialog-action-close": "دایخە"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/co.json b/resources/oojs-ui/i18n/co.json
new file mode 100644 (file)
index 0000000..e5edb21
--- /dev/null
@@ -0,0 +1,10 @@
+{
+    "@metadata": {
+        "authors": [
+            "Paulu"
+        ]
+    },
+    "ooui-dialog-action-close": "Chjude",
+    "ooui-outline-control-move-down": "Fà falà l'ogettu",
+    "ooui-outline-control-move-up": "Fà cullà l'ogettu"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/cs.json b/resources/oojs-ui/i18n/cs.json
new file mode 100644 (file)
index 0000000..9661ec6
--- /dev/null
@@ -0,0 +1,20 @@
+{
+    "@metadata": {
+        "authors": [
+            "Chmee2",
+            "Jkjk",
+            "Juandev",
+            "Koo6",
+            "Littledogboy",
+            "Michaelbrabec",
+            "Mormegil",
+            "Polda18",
+            "Tchoř",
+            "ශ්වෙත"
+        ]
+    },
+    "ooui-dialog-action-close": "Zavřít",
+    "ooui-outline-control-move-down": "Přesunout položku dolů",
+    "ooui-outline-control-move-up": "Přesunout položku nahoru",
+    "ooui-toolbar-more": "Další"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/cu.json b/resources/oojs-ui/i18n/cu.json
new file mode 100644 (file)
index 0000000..fa9b1cf
--- /dev/null
@@ -0,0 +1,8 @@
+{
+    "@metadata": {
+        "authors": [
+            "ОйЛ"
+        ]
+    },
+    "ooui-dialog-action-close": "ꙁакрꙑи"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/cy.json b/resources/oojs-ui/i18n/cy.json
new file mode 100644 (file)
index 0000000..d37912d
--- /dev/null
@@ -0,0 +1,13 @@
+{
+    "@metadata": {
+        "authors": [
+            "Lloffiwr",
+            "Robin Owain",
+            "ОйЛ"
+        ]
+    },
+    "ooui-dialog-action-close": "Caeer",
+    "ooui-outline-control-move-down": "Symud yr eitem lawr",
+    "ooui-outline-control-move-up": "Symud yr eitem lan",
+    "ooui-toolbar-more": "Rhagor"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/da.json b/resources/oojs-ui/i18n/da.json
new file mode 100644 (file)
index 0000000..bf47bcb
--- /dev/null
@@ -0,0 +1,17 @@
+{
+    "@metadata": {
+        "authors": [
+            "Cgtdk",
+            "Christian List",
+            "EileenSanda",
+            "Laketown",
+            "Palnatoke",
+            "Simeondahl",
+            "Tehnix"
+        ]
+    },
+    "ooui-dialog-action-close": "Luk",
+    "ooui-outline-control-move-down": "Flyt ned",
+    "ooui-outline-control-move-up": "Flyt op",
+    "ooui-toolbar-more": "Mere"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/de.json b/resources/oojs-ui/i18n/de.json
new file mode 100644 (file)
index 0000000..3a66648
--- /dev/null
@@ -0,0 +1,20 @@
+{
+    "@metadata": {
+        "authors": [
+            "APPER",
+            "G.Hagedorn",
+            "Inkowik",
+            "Jcornelius",
+            "Jdforrester",
+            "Kghbln",
+            "Metalhead64",
+            "Murma174",
+            "Se4598",
+            "Tomabrafix"
+        ]
+    },
+    "ooui-dialog-action-close": "Schließen",
+    "ooui-outline-control-move-down": "Element nach unten verschieben",
+    "ooui-outline-control-move-up": "Element nach oben verschieben",
+    "ooui-toolbar-more": "Mehr"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/diq.json b/resources/oojs-ui/i18n/diq.json
new file mode 100644 (file)
index 0000000..bb0ac35
--- /dev/null
@@ -0,0 +1,16 @@
+{
+    "@metadata": {
+        "authors": [
+            "Erdemaslancan",
+            "Gorizon",
+            "Kghbln",
+            "Marmase",
+            "Mirzali",
+            "Se4598"
+        ]
+    },
+    "ooui-dialog-action-close": "Racnê",
+    "ooui-outline-control-move-down": "Bendi bere cêr",
+    "ooui-outline-control-move-up": "Bendi bere cor",
+    "ooui-toolbar-more": "Zewbi"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/dsb.json b/resources/oojs-ui/i18n/dsb.json
new file mode 100644 (file)
index 0000000..0f47587
--- /dev/null
@@ -0,0 +1,11 @@
+{
+    "@metadata": {
+        "authors": [
+            "Michawiki"
+        ]
+    },
+    "ooui-dialog-action-close": "Zacyniś",
+    "ooui-outline-control-move-down": "Element dołoj pśesunuś",
+    "ooui-outline-control-move-up": "Element górjej pśesunuś",
+    "ooui-toolbar-more": "Wěcej"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/el.json b/resources/oojs-ui/i18n/el.json
new file mode 100644 (file)
index 0000000..66051f1
--- /dev/null
@@ -0,0 +1,18 @@
+{
+    "@metadata": {
+        "authors": [
+            "Astralnet",
+            "Dipa1965",
+            "Evropi",
+            "FocalPoint",
+            "Geraki",
+            "Glavkos",
+            "Nikosguard",
+            "Tifa93"
+        ]
+    },
+    "ooui-dialog-action-close": "Κλείσιμο",
+    "ooui-outline-control-move-down": "Μετακίνηση προς τα κάτω",
+    "ooui-outline-control-move-up": "Μετακίνηση προς τα πάνω",
+    "ooui-toolbar-more": "Περισσότερα"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/eml.json b/resources/oojs-ui/i18n/eml.json
new file mode 100644 (file)
index 0000000..5dd09f5
--- /dev/null
@@ -0,0 +1,12 @@
+{
+    "@metadata": {
+        "authors": [
+            "Gloria sah",
+            "Lévi"
+        ]
+    },
+    "ooui-dialog-action-close": "Sèra",
+    "ooui-outline-control-move-down": "Spôsta in bâs",
+    "ooui-outline-control-move-up": "Spôsta in êlt",
+    "ooui-toolbar-more": "Êter"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/en.json b/resources/oojs-ui/i18n/en.json
new file mode 100644 (file)
index 0000000..d402de8
--- /dev/null
@@ -0,0 +1,23 @@
+{
+    "@metadata": {
+        "authors": [
+            "Trevor Parscal",
+            "Ed Sanders",
+            "James D. Forrester",
+            "Raimond Spekking",
+            "Erik Moeller",
+            "Moriel Schottlender",
+            "Yuki Shira",
+            "Siebrand Mazeland",
+            "Rob Moen",
+            "Timo Tijhof",
+            "Roan Kattouw",
+            "Christian Williams",
+            "Amir E. Aharoni"
+        ]
+    },
+    "ooui-dialog-action-close": "Close",
+    "ooui-outline-control-move-down": "Move item down",
+    "ooui-outline-control-move-up": "Move item up",
+    "ooui-toolbar-more": "More"
+}
diff --git a/resources/oojs-ui/i18n/eo.json b/resources/oojs-ui/i18n/eo.json
new file mode 100644 (file)
index 0000000..51f3261
--- /dev/null
@@ -0,0 +1,14 @@
+{
+    "@metadata": {
+        "authors": [
+            "Happy5214",
+            "KuboF",
+            "Shirayuki",
+            "Yekrats"
+        ]
+    },
+    "ooui-dialog-action-close": "Fermi",
+    "ooui-outline-control-move-down": "Movi eron suben",
+    "ooui-outline-control-move-up": "Movi eron supren",
+    "ooui-toolbar-more": "Pli"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/es.json b/resources/oojs-ui/i18n/es.json
new file mode 100644 (file)
index 0000000..0d822bc
--- /dev/null
@@ -0,0 +1,23 @@
+{
+    "@metadata": {
+        "authors": [
+            "Armando-Martin",
+            "Aruizdr",
+            "Benfutbol10",
+            "DJ Nietzsche",
+            "Erdemaslancan",
+            "Fitoschido",
+            "Imre",
+            "Invadinado",
+            "Jdforrester",
+            "Jduranboger",
+            "PoLuX124",
+            "Ralgis",
+            "Thehelpfulone"
+        ]
+    },
+    "ooui-dialog-action-close": "Cerrar",
+    "ooui-outline-control-move-down": "Mover abajo",
+    "ooui-outline-control-move-up": "Mover arriba",
+    "ooui-toolbar-more": "Más"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/et.json b/resources/oojs-ui/i18n/et.json
new file mode 100644 (file)
index 0000000..4af8dbe
--- /dev/null
@@ -0,0 +1,12 @@
+{
+    "@metadata": {
+        "authors": [
+            "Avjoska",
+            "Pikne"
+        ]
+    },
+    "ooui-dialog-action-close": "Sule",
+    "ooui-outline-control-move-down": "Liiguta üksust allapoole",
+    "ooui-outline-control-move-up": "Liiguta üksust ülespoole",
+    "ooui-toolbar-more": "Veel"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/eu.json b/resources/oojs-ui/i18n/eu.json
new file mode 100644 (file)
index 0000000..5d3f08b
--- /dev/null
@@ -0,0 +1,13 @@
+{
+    "@metadata": {
+        "authors": [
+            "An13sa",
+            "Unai Fdz. de Betoño",
+            "Xabier Armendaritz"
+        ]
+    },
+    "ooui-dialog-action-close": "Itxi",
+    "ooui-outline-control-move-down": "Mugitu itema beherantz",
+    "ooui-outline-control-move-up": "Mugitu itema gorantz",
+    "ooui-toolbar-more": "Gehiago"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/fa.json b/resources/oojs-ui/i18n/fa.json
new file mode 100644 (file)
index 0000000..173acd7
--- /dev/null
@@ -0,0 +1,19 @@
+{
+    "@metadata": {
+        "authors": [
+            "Dalba",
+            "Ebraminio",
+            "Jdforrester",
+            "Ladsgroup",
+            "Mjbmr",
+            "Nojan Madinehi",
+            "Reza1615",
+            "Taha",
+            "درفش کاویانی"
+        ]
+    },
+    "ooui-dialog-action-close": "بستن",
+    "ooui-outline-control-move-down": "انتقال مورد به پایین",
+    "ooui-outline-control-move-up": "انتقال مورد به بالا",
+    "ooui-toolbar-more": "بیشتر"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/fi.json b/resources/oojs-ui/i18n/fi.json
new file mode 100644 (file)
index 0000000..dcd367f
--- /dev/null
@@ -0,0 +1,23 @@
+{
+    "@metadata": {
+        "authors": [
+            "Beluga",
+            "Crt",
+            "Harriv",
+            "Linnea",
+            "Nedergard",
+            "Nike",
+            "Olli",
+            "Pxos",
+            "Samoasambia",
+            "Silvonen",
+            "Skalman",
+            "Stryn",
+            "VezonThunder"
+        ]
+    },
+    "ooui-dialog-action-close": "Sulje",
+    "ooui-outline-control-move-down": "Siirrä kohdetta alaspäin",
+    "ooui-outline-control-move-up": "Siirrä kohdetta ylöspäin",
+    "ooui-toolbar-more": "Lisää"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/fo.json b/resources/oojs-ui/i18n/fo.json
new file mode 100644 (file)
index 0000000..00a48ff
--- /dev/null
@@ -0,0 +1,11 @@
+{
+    "@metadata": {
+        "authors": [
+            "EileenSanda"
+        ]
+    },
+    "ooui-dialog-action-close": "Lat aftur",
+    "ooui-outline-control-move-down": "Flyt lutin niður",
+    "ooui-outline-control-move-up": "Flyt lutin upp",
+    "ooui-toolbar-more": "Meira"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/fr.json b/resources/oojs-ui/i18n/fr.json
new file mode 100644 (file)
index 0000000..eb24b5a
--- /dev/null
@@ -0,0 +1,35 @@
+{
+    "@metadata": {
+        "authors": [
+            "Automatik",
+            "Benoit Rochon",
+            "Boniface",
+            "Brunoperel",
+            "Crochet.david",
+            "DavidL",
+            "Dereckson",
+            "Gomoko",
+            "Guillom",
+            "Hello71",
+            "Jean-Frédéric",
+            "Linedwell",
+            "Ltrlg",
+            "Metroitendo",
+            "NemesisIII",
+            "Nicolas NALLET",
+            "Npettiaux",
+            "Rastus Vernon",
+            "Seb35",
+            "Sherbrooke",
+            "Tpt",
+            "Trizek",
+            "Urhixidur",
+            "Verdy p",
+            "Wyz"
+        ]
+    },
+    "ooui-dialog-action-close": "Fermer",
+    "ooui-outline-control-move-down": "Faire descendre l’élément",
+    "ooui-outline-control-move-up": "Faire monter l’élément",
+    "ooui-toolbar-more": "Plus"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/frr.json b/resources/oojs-ui/i18n/frr.json
new file mode 100644 (file)
index 0000000..ee95b8a
--- /dev/null
@@ -0,0 +1,12 @@
+{
+    "@metadata": {
+        "authors": [
+            "ChrisPtDe",
+            "Murma174"
+        ]
+    },
+    "ooui-dialog-action-close": "Slütj",
+    "ooui-outline-control-move-down": "Element efter onern sküüw",
+    "ooui-outline-control-move-up": "Element efter boowen sküüw",
+    "ooui-toolbar-more": "Muar"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/fur.json b/resources/oojs-ui/i18n/fur.json
new file mode 100644 (file)
index 0000000..18ea383
--- /dev/null
@@ -0,0 +1,12 @@
+{
+    "@metadata": {
+        "authors": [
+            "Klenje",
+            "Tocaibon"
+        ]
+    },
+    "ooui-dialog-action-close": "Siere",
+    "ooui-outline-control-move-down": "sposte sot",
+    "ooui-outline-control-move-up": "sposte in su",
+    "ooui-toolbar-more": "Altri"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/gl.json b/resources/oojs-ui/i18n/gl.json
new file mode 100644 (file)
index 0000000..5d0928f
--- /dev/null
@@ -0,0 +1,13 @@
+{
+    "@metadata": {
+        "authors": [
+            "Alison",
+            "Kscanne",
+            "Toliño"
+        ]
+    },
+    "ooui-dialog-action-close": "Pechar",
+    "ooui-outline-control-move-down": "Mover o elemento abaixo",
+    "ooui-outline-control-move-up": "Mover o elemento arriba",
+    "ooui-toolbar-more": "Máis"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/gu.json b/resources/oojs-ui/i18n/gu.json
new file mode 100644 (file)
index 0000000..65ec22b
--- /dev/null
@@ -0,0 +1,13 @@
+{
+    "@metadata": {
+        "authors": [
+            "Ashok modhvadia",
+            "KartikMistry",
+            "The Discoverer"
+        ]
+    },
+    "ooui-dialog-action-close": "બંધ કરો",
+    "ooui-outline-control-move-down": "વસ્તુ નીચે ખસેડો",
+    "ooui-outline-control-move-up": "વસ્તુ ઉપર ખસેડો",
+    "ooui-toolbar-more": "વધુ"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/he.json b/resources/oojs-ui/i18n/he.json
new file mode 100644 (file)
index 0000000..31b693c
--- /dev/null
@@ -0,0 +1,22 @@
+{
+    "@metadata": {
+        "authors": [
+            "Amire80",
+            "ExampleTomer",
+            "Guycn2",
+            "Matanya",
+            "Mooeypoo",
+            "Orsa",
+            "Shimmin Beg",
+            "אור שפירא",
+            "חיים",
+            "ערן",
+            "פוילישער",
+            "קיפודנחש"
+        ]
+    },
+    "ooui-dialog-action-close": "סגירה",
+    "ooui-outline-control-move-down": "להזיז את הפריט מטה",
+    "ooui-outline-control-move-up": "להזיז את הפריט מעלה",
+    "ooui-toolbar-more": "עוד"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/hi.json b/resources/oojs-ui/i18n/hi.json
new file mode 100644 (file)
index 0000000..8b79d34
--- /dev/null
@@ -0,0 +1,14 @@
+{
+    "@metadata": {
+        "authors": [
+            "Ansumang",
+            "Devayon",
+            "Rajesh",
+            "Siddhartha Ghai"
+        ]
+    },
+    "ooui-dialog-action-close": "बंद करें",
+    "ooui-outline-control-move-down": "प्रविष्टि नीचे ले जाएँ",
+    "ooui-outline-control-move-up": "प्रविष्टि ऊपर ले जाएँ",
+    "ooui-toolbar-more": "अधिक"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/hr.json b/resources/oojs-ui/i18n/hr.json
new file mode 100644 (file)
index 0000000..1c3f925
--- /dev/null
@@ -0,0 +1,13 @@
+{
+    "@metadata": {
+        "authors": [
+            "MaGa",
+            "Roberta F.",
+            "SpeedyGonsales"
+        ]
+    },
+    "ooui-dialog-action-close": "zatvori",
+    "ooui-outline-control-move-down": "Premjesti stavku dolje",
+    "ooui-outline-control-move-up": "Premjesti stavku gore",
+    "ooui-toolbar-more": "Više mogućnosti"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/hsb.json b/resources/oojs-ui/i18n/hsb.json
new file mode 100644 (file)
index 0000000..861c6e5
--- /dev/null
@@ -0,0 +1,9 @@
+{
+    "@metadata": {
+        "authors": [
+            "J budissin",
+            "Michawiki"
+        ]
+    },
+    "ooui-dialog-action-close": "Začinić"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/hu.json b/resources/oojs-ui/i18n/hu.json
new file mode 100644 (file)
index 0000000..9f7b435
--- /dev/null
@@ -0,0 +1,14 @@
+{
+    "@metadata": {
+        "authors": [
+            "Dj",
+            "Einstein2",
+            "Misibacsi",
+            "ViDam"
+        ]
+    },
+    "ooui-dialog-action-close": "Bezár",
+    "ooui-outline-control-move-down": "Elem mozgatása lefelé",
+    "ooui-outline-control-move-up": "Elem mozgatása felfelé",
+    "ooui-toolbar-more": "Tovább..."
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/hy.json b/resources/oojs-ui/i18n/hy.json
new file mode 100644 (file)
index 0000000..f6cb90b
--- /dev/null
@@ -0,0 +1,12 @@
+{
+    "@metadata": {
+        "authors": [
+            "Vacio",
+            "Xelgen"
+        ]
+    },
+    "ooui-dialog-action-close": "Փակել",
+    "ooui-outline-control-move-down": "Իջեցնել կետը",
+    "ooui-outline-control-move-up": "Բարձրացնել կետը",
+    "ooui-toolbar-more": "Ավելին"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/ia.json b/resources/oojs-ui/i18n/ia.json
new file mode 100644 (file)
index 0000000..e335553
--- /dev/null
@@ -0,0 +1,8 @@
+{
+    "@metadata": {
+        "authors": [
+            "McDutchie"
+        ]
+    },
+    "ooui-dialog-action-close": "Clauder"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/id.json b/resources/oojs-ui/i18n/id.json
new file mode 100644 (file)
index 0000000..6d3ba4d
--- /dev/null
@@ -0,0 +1,18 @@
+{
+    "@metadata": {
+        "authors": [
+            "Farras",
+            "Ilham151096",
+            "Iwan Novirion",
+            "Iyan",
+            "Kenrick95",
+            "McDutchie",
+            "Rv77ax",
+            "William Surya Permana"
+        ]
+    },
+    "ooui-dialog-action-close": "Tutup",
+    "ooui-outline-control-move-down": "Pindahkan butir ke bawah",
+    "ooui-outline-control-move-up": "Pindahkan butir ke atas",
+    "ooui-toolbar-more": "Lainnya"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/ie.json b/resources/oojs-ui/i18n/ie.json
new file mode 100644 (file)
index 0000000..84d002d
--- /dev/null
@@ -0,0 +1,11 @@
+{
+    "@metadata": {
+        "authors": [
+            "Makuba"
+        ]
+    },
+    "ooui-dialog-action-close": "Terminar",
+    "ooui-outline-control-move-down": "Mover element a infra",
+    "ooui-outline-control-move-up": "Mover element a supra",
+    "ooui-toolbar-more": "Plu"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/ilo.json b/resources/oojs-ui/i18n/ilo.json
new file mode 100644 (file)
index 0000000..15f42e5
--- /dev/null
@@ -0,0 +1,11 @@
+{
+    "@metadata": {
+        "authors": [
+            "Lam-ang"
+        ]
+    },
+    "ooui-dialog-action-close": "Irekep",
+    "ooui-outline-control-move-down": "Ipababa ti banag",
+    "ooui-outline-control-move-up": "Ipangato ti banag",
+    "ooui-toolbar-more": "Adu pay"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/is.json b/resources/oojs-ui/i18n/is.json
new file mode 100644 (file)
index 0000000..efe0e67
--- /dev/null
@@ -0,0 +1,12 @@
+{
+    "@metadata": {
+        "authors": [
+            "Maxí",
+            "Snævar"
+        ]
+    },
+    "ooui-dialog-action-close": "Loka",
+    "ooui-outline-control-move-down": "Færa atriða niður",
+    "ooui-outline-control-move-up": "Færa atriða upp",
+    "ooui-toolbar-more": "Fleira"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/it.json b/resources/oojs-ui/i18n/it.json
new file mode 100644 (file)
index 0000000..6158cff
--- /dev/null
@@ -0,0 +1,21 @@
+{
+    "@metadata": {
+        "authors": [
+            "Beta16",
+            "Darth Kule",
+            "Doc.mari",
+            "Eleonora negri",
+            "Elitre",
+            "F. Cosoleto",
+            "FRacco",
+            "Gianfranco",
+            "Minerva Titani",
+            "Raoli",
+            "Una giornata uggiosa '94"
+        ]
+    },
+    "ooui-dialog-action-close": "Chiudi",
+    "ooui-outline-control-move-down": "Sposta in basso",
+    "ooui-outline-control-move-up": "Sposta in alto",
+    "ooui-toolbar-more": "Altro"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/ja.json b/resources/oojs-ui/i18n/ja.json
new file mode 100644 (file)
index 0000000..789fbeb
--- /dev/null
@@ -0,0 +1,14 @@
+{
+    "@metadata": {
+        "authors": [
+            "Fryed-peach",
+            "Miya",
+            "Penn Station",
+            "Shirayuki"
+        ]
+    },
+    "ooui-dialog-action-close": "閉じる",
+    "ooui-outline-control-move-down": "項目を下に移動させる",
+    "ooui-outline-control-move-up": "項目を上に移動させる",
+    "ooui-toolbar-more": "その他"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/jv.json b/resources/oojs-ui/i18n/jv.json
new file mode 100644 (file)
index 0000000..a362079
--- /dev/null
@@ -0,0 +1,11 @@
+{
+    "@metadata": {
+        "authors": [
+            "Gleki",
+            "NoiX180",
+            "Pras"
+        ]
+    },
+    "ooui-dialog-action-close": "Tutup",
+    "ooui-outline-control-move-down": "Pindhahaken butir mangandhap"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/ka.json b/resources/oojs-ui/i18n/ka.json
new file mode 100644 (file)
index 0000000..78180af
--- /dev/null
@@ -0,0 +1,16 @@
+{
+    "@metadata": {
+        "authors": [
+            "BRUTE",
+            "David1010",
+            "Gleki",
+            "ITshnik",
+            "MIKHEIL",
+            "NoiX180",
+            "Pras"
+        ]
+    },
+    "ooui-dialog-action-close": "დახურვა",
+    "ooui-outline-control-move-down": "ელემენტის ქვემოთ გადატანა",
+    "ooui-outline-control-move-up": "ელემენტის ზემოთ გადატანა"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/kk-cyrl.json b/resources/oojs-ui/i18n/kk-cyrl.json
new file mode 100644 (file)
index 0000000..4c27b07
--- /dev/null
@@ -0,0 +1,11 @@
+{
+    "@metadata": {
+        "authors": [
+            "Arystanbek"
+        ]
+    },
+    "ooui-dialog-action-close": "Жабу",
+    "ooui-outline-control-move-down": "Элементті төмен жылжыту",
+    "ooui-outline-control-move-up": "Элементті жоғары жылжыту",
+    "ooui-toolbar-more": "толығырақ"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/km.json b/resources/oojs-ui/i18n/km.json
new file mode 100644 (file)
index 0000000..2013ee3
--- /dev/null
@@ -0,0 +1,11 @@
+{
+    "@metadata": {
+        "authors": [
+            "Sovichet"
+        ]
+    },
+    "ooui-dialog-action-close": "បិទ",
+    "ooui-outline-control-move-down": "រុញ​ទៅ​ក្រោម",
+    "ooui-outline-control-move-up": "រុញ​ទៅ​លើ",
+    "ooui-toolbar-more": "បន្ថែម"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/ko.json b/resources/oojs-ui/i18n/ko.json
new file mode 100644 (file)
index 0000000..f1f61df
--- /dev/null
@@ -0,0 +1,15 @@
+{
+    "@metadata": {
+        "authors": [
+            "Freebiekr",
+            "Hym411",
+            "Kwj2772",
+            "LFM",
+            "아라"
+        ]
+    },
+    "ooui-dialog-action-close": "닫기",
+    "ooui-outline-control-move-down": "항목을 아래로 옮기기",
+    "ooui-outline-control-move-up": "항목을 위로 옮기기",
+    "ooui-toolbar-more": "더 보기"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/krc.json b/resources/oojs-ui/i18n/krc.json
new file mode 100644 (file)
index 0000000..f629139
--- /dev/null
@@ -0,0 +1,10 @@
+{
+    "@metadata": {
+        "authors": [
+            "Iltever"
+        ]
+    },
+    "ooui-dialog-action-close": "Джаб",
+    "ooui-outline-control-move-down": "Элементни тюбюне кёчюр",
+    "ooui-outline-control-move-up": "Элементни башына кёчюр"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/kw.json b/resources/oojs-ui/i18n/kw.json
new file mode 100644 (file)
index 0000000..95a9b91
--- /dev/null
@@ -0,0 +1,10 @@
+{
+    "@metadata": {
+        "authors": [
+            "George Animal",
+            "Nrowe",
+            "Purodha"
+        ]
+    },
+    "ooui-dialog-action-close": "Degea"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/ky.json b/resources/oojs-ui/i18n/ky.json
new file mode 100644 (file)
index 0000000..2d62bda
--- /dev/null
@@ -0,0 +1,12 @@
+{
+    "@metadata": {
+        "authors": [
+            "Chorobek",
+            "George Animal",
+            "Nrowe",
+            "Tynchtyk Chorotegin",
+            "Викиней"
+        ]
+    },
+    "ooui-dialog-action-close": "Жабуу"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/lb.json b/resources/oojs-ui/i18n/lb.json
new file mode 100644 (file)
index 0000000..a18894e
--- /dev/null
@@ -0,0 +1,17 @@
+{
+    "@metadata": {
+        "authors": [
+            "Autokrator",
+            "Chorobek",
+            "Robby",
+            "Soued031",
+            "Tynchtyk Chorotegin",
+            "UV",
+            "Викиней"
+        ]
+    },
+    "ooui-dialog-action-close": "Zoumaachen",
+    "ooui-outline-control-move-down": "Element erof réckelen",
+    "ooui-outline-control-move-up": "Element erop réckelen",
+    "ooui-toolbar-more": "Méi"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/lmo.json b/resources/oojs-ui/i18n/lmo.json
new file mode 100644 (file)
index 0000000..e506b7a
--- /dev/null
@@ -0,0 +1,11 @@
+{
+    "@metadata": {
+        "authors": [
+            "Ninonino"
+        ]
+    },
+    "ooui-dialog-action-close": "Sèra",
+    "ooui-outline-control-move-down": "Spòsta 'n zó",
+    "ooui-outline-control-move-up": "Spòsta 'n sö",
+    "ooui-toolbar-more": "Amò"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/lt.json b/resources/oojs-ui/i18n/lt.json
new file mode 100644 (file)
index 0000000..b3a16e8
--- /dev/null
@@ -0,0 +1,9 @@
+{
+    "@metadata": {
+        "authors": [
+            "Audriusa",
+            "Eitvys200"
+        ]
+    },
+    "ooui-dialog-action-close": "Uždaryti"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/lv.json b/resources/oojs-ui/i18n/lv.json
new file mode 100644 (file)
index 0000000..c633339
--- /dev/null
@@ -0,0 +1,15 @@
+{
+    "@metadata": {
+        "authors": [
+            "Admresdeserv.",
+            "Audriusa",
+            "Eitvys200",
+            "Papuass",
+            "PeterisP"
+        ]
+    },
+    "ooui-dialog-action-close": "Aizvērt",
+    "ooui-outline-control-move-down": "Pārvietot vienumu uz leju",
+    "ooui-outline-control-move-up": "Pārvietot vienumu uz augšu",
+    "ooui-toolbar-more": "Vairāk"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/mg.json b/resources/oojs-ui/i18n/mg.json
new file mode 100644 (file)
index 0000000..dcb5fd5
--- /dev/null
@@ -0,0 +1,8 @@
+{
+    "@metadata": {
+        "authors": [
+            "Jagwar"
+        ]
+    },
+    "ooui-dialog-action-close": "Hidiana"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/min.json b/resources/oojs-ui/i18n/min.json
new file mode 100644 (file)
index 0000000..55174c0
--- /dev/null
@@ -0,0 +1,9 @@
+{
+    "@metadata": {
+        "authors": [
+            "Iwan Novirion",
+            "Jagwar"
+        ]
+    },
+    "ooui-dialog-action-close": "Tutuik"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/mk.json b/resources/oojs-ui/i18n/mk.json
new file mode 100644 (file)
index 0000000..b363a45
--- /dev/null
@@ -0,0 +1,13 @@
+{
+    "@metadata": {
+        "authors": [
+            "Bjankuloski06",
+            "Brest",
+            "Iwan Novirion"
+        ]
+    },
+    "ooui-dialog-action-close": "Затвори",
+    "ooui-outline-control-move-down": "Помести надолу",
+    "ooui-outline-control-move-up": "Помести нагоре",
+    "ooui-toolbar-more": "Повеќе"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/ml.json b/resources/oojs-ui/i18n/ml.json
new file mode 100644 (file)
index 0000000..355e337
--- /dev/null
@@ -0,0 +1,14 @@
+{
+    "@metadata": {
+        "authors": [
+            "Kavya Manohar",
+            "Praveenp",
+            "Santhosh.thottingal",
+            "Vssun"
+        ]
+    },
+    "ooui-dialog-action-close": "അടയ്ക്കുക",
+    "ooui-outline-control-move-down": "ഇനം താഴേയ്ക്ക് മാറ്റുക",
+    "ooui-outline-control-move-up": "ഇനം മുകളിലേയ്ക്ക് മാറ്റുക",
+    "ooui-toolbar-more": "കൂടുതൽ"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/mr.json b/resources/oojs-ui/i18n/mr.json
new file mode 100644 (file)
index 0000000..d4db84f
--- /dev/null
@@ -0,0 +1,16 @@
+{
+    "@metadata": {
+        "authors": [
+            "Kaajawa",
+            "Mahitgar",
+            "Praju23",
+            "V.narsikar",
+            "Ydyashad",
+            "संतोष दहिवळ"
+        ]
+    },
+    "ooui-dialog-action-close": "बंद करा",
+    "ooui-outline-control-move-down": "घटक (आयटम) खाली सरकवा",
+    "ooui-outline-control-move-up": "घटक (आयटम) वर सरकवा",
+    "ooui-toolbar-more": "अधिक"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/ms.json b/resources/oojs-ui/i18n/ms.json
new file mode 100644 (file)
index 0000000..21aef50
--- /dev/null
@@ -0,0 +1,12 @@
+{
+    "@metadata": {
+        "authors": [
+            "Anakmalaysia",
+            "Aurora"
+        ]
+    },
+    "ooui-dialog-action-close": "Tutup",
+    "ooui-outline-control-move-down": "Alihkan perkara ke bawah",
+    "ooui-outline-control-move-up": "Alihkan perkara ke atas",
+    "ooui-toolbar-more": "Lagi"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/nap.json b/resources/oojs-ui/i18n/nap.json
new file mode 100644 (file)
index 0000000..6b0b3ec
--- /dev/null
@@ -0,0 +1,11 @@
+{
+    "@metadata": {
+        "authors": [
+            "Chelin",
+            "Chrisportelli",
+            "PiRSquared17"
+        ]
+    },
+    "ooui-dialog-action-close": "Chiure",
+    "ooui-toolbar-more": "Atro"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/nb.json b/resources/oojs-ui/i18n/nb.json
new file mode 100644 (file)
index 0000000..7cdecaa
--- /dev/null
@@ -0,0 +1,15 @@
+{
+    "@metadata": {
+        "authors": [
+            "Danmichaelo",
+            "Event",
+            "Jeblad",
+            "Laaknor",
+            "Njardarlogar"
+        ]
+    },
+    "ooui-dialog-action-close": "Lukk",
+    "ooui-outline-control-move-down": "Flytt ned",
+    "ooui-outline-control-move-up": "Flytt opp",
+    "ooui-toolbar-more": "Mer"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/nds-nl.json b/resources/oojs-ui/i18n/nds-nl.json
new file mode 100644 (file)
index 0000000..81f8a43
--- /dev/null
@@ -0,0 +1,10 @@
+{
+    "@metadata": {
+        "authors": [
+            "Servien"
+        ]
+    },
+    "ooui-dialog-action-close": "Sluten",
+    "ooui-outline-control-move-down": "Onderwarp ummeneer zetten",
+    "ooui-outline-control-move-up": "Onderwarp umhoge zetten"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/nds.json b/resources/oojs-ui/i18n/nds.json
new file mode 100644 (file)
index 0000000..d0806d0
--- /dev/null
@@ -0,0 +1,11 @@
+{
+    "@metadata": {
+        "authors": [
+            "Zylbath"
+        ]
+    },
+    "ooui-dialog-action-close": "Dichtmaken",
+    "ooui-outline-control-move-down": "Element na ünnen schuven",
+    "ooui-outline-control-move-up": "Element na baven schuven",
+    "ooui-toolbar-more": "Mehr"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/ne.json b/resources/oojs-ui/i18n/ne.json
new file mode 100644 (file)
index 0000000..ae948c6
--- /dev/null
@@ -0,0 +1,8 @@
+{
+    "@metadata": {
+        "authors": [
+            "RajeshPandey",
+            "सरोज कुमार ढकाल"
+        ]
+    }
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/nl.json b/resources/oojs-ui/i18n/nl.json
new file mode 100644 (file)
index 0000000..75db0a7
--- /dev/null
@@ -0,0 +1,25 @@
+{
+    "@metadata": {
+        "authors": [
+            "Bluyten",
+            "Breghtje",
+            "Catrope",
+            "Flightmare",
+            "Hansmuller",
+            "Jdforrester",
+            "Keegan",
+            "Konovalov",
+            "RajeshPandey",
+            "Romaine",
+            "SPQRobin",
+            "Saruman",
+            "Siebrand",
+            "Southparkfan",
+            "सरोज कुमार ढकाल"
+        ]
+    },
+    "ooui-dialog-action-close": "Sluiten",
+    "ooui-outline-control-move-down": "Item omlaag verplaatsen",
+    "ooui-outline-control-move-up": "Item omhoog verplaatsen",
+    "ooui-toolbar-more": "Meer"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/nn.json b/resources/oojs-ui/i18n/nn.json
new file mode 100644 (file)
index 0000000..dd86f5e
--- /dev/null
@@ -0,0 +1,12 @@
+{
+    "@metadata": {
+        "authors": [
+            "Jeblad",
+            "Njardarlogar"
+        ]
+    },
+    "ooui-dialog-action-close": "Lat att",
+    "ooui-outline-control-move-down": "Flytt element ned",
+    "ooui-outline-control-move-up": "Flytt element opp",
+    "ooui-toolbar-more": "Fleire"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/om.json b/resources/oojs-ui/i18n/om.json
new file mode 100644 (file)
index 0000000..dca7b7d
--- /dev/null
@@ -0,0 +1,12 @@
+{
+    "@metadata": {
+        "authors": [
+            "Cedric31",
+            "Tumsaa"
+        ]
+    },
+    "ooui-dialog-action-close": "Cufi",
+    "ooui-outline-control-move-down": "Gad buusi",
+    "ooui-outline-control-move-up": "Ol baasi",
+    "ooui-toolbar-more": "Dabalata"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/or.json b/resources/oojs-ui/i18n/or.json
new file mode 100644 (file)
index 0000000..35721a1
--- /dev/null
@@ -0,0 +1,10 @@
+{
+    "@metadata": {
+        "authors": [
+            "Odisha1",
+            "Psubhashish",
+            "ଶିତିକଣ୍ଠ ଦାଶ"
+        ]
+    },
+    "ooui-dialog-action-close": "ବନ୍ଦ କରିବେ"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/pa.json b/resources/oojs-ui/i18n/pa.json
new file mode 100644 (file)
index 0000000..6c76d7f
--- /dev/null
@@ -0,0 +1,11 @@
+{
+    "@metadata": {
+        "authors": [
+            "Amikeco",
+            "Babanwalia",
+            "Bouron",
+            "Nasir8891"
+        ]
+    },
+    "ooui-dialog-action-close": "বন্ধ"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/pl.json b/resources/oojs-ui/i18n/pl.json
new file mode 100644 (file)
index 0000000..ba33322
--- /dev/null
@@ -0,0 +1,22 @@
+{
+    "@metadata": {
+        "authors": [
+            "Babanwalia",
+            "Chrumps",
+            "Matma Rex",
+            "Mikołka",
+            "Nasir8891",
+            "Odie2",
+            "Rzuwig",
+            "Tar Lócesilion",
+            "Ty221",
+            "WTM",
+            "Woytecr",
+            "Wpedzich"
+        ]
+    },
+    "ooui-dialog-action-close": "Zamknij",
+    "ooui-outline-control-move-down": "Przenieś niżej",
+    "ooui-outline-control-move-up": "Przenieś wyżej",
+    "ooui-toolbar-more": "Więcej"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/pms.json b/resources/oojs-ui/i18n/pms.json
new file mode 100644 (file)
index 0000000..bb8f113
--- /dev/null
@@ -0,0 +1,13 @@
+{
+    "@metadata": {
+        "authors": [
+            "Borichèt",
+            "Dragonòt",
+            "පසිඳු කාවින්ද"
+        ]
+    },
+    "ooui-dialog-action-close": "Saré",
+    "ooui-outline-control-move-down": "Fé calé giù l'element",
+    "ooui-outline-control-move-up": "Fé monté l'element",
+    "ooui-toolbar-more": "Ëd pi"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/ps.json b/resources/oojs-ui/i18n/ps.json
new file mode 100644 (file)
index 0000000..4f21707
--- /dev/null
@@ -0,0 +1,11 @@
+{
+    "@metadata": {
+        "authors": [
+            "Ahmed-Najib-Biabani-Ibrahimkhel"
+        ]
+    },
+    "ooui-dialog-action-close": "تړل",
+    "ooui-outline-control-move-down": "توکی ښکته راوړل",
+    "ooui-outline-control-move-up": "توکی پورته راوړل",
+    "ooui-toolbar-more": "نور"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/pt-br.json b/resources/oojs-ui/i18n/pt-br.json
new file mode 100644 (file)
index 0000000..f758660
--- /dev/null
@@ -0,0 +1,19 @@
+{
+    "@metadata": {
+        "authors": [
+            "Cainamarques",
+            "Dianakc",
+            "Fúlvio",
+            "Helder.wiki",
+            "HenriqueCrang",
+            "Jaideraf",
+            "Luckas",
+            "OTAVIO1981",
+            555
+        ]
+    },
+    "ooui-dialog-action-close": "Fechar",
+    "ooui-outline-control-move-down": "Mover item para baixo",
+    "ooui-outline-control-move-up": "Mover item para cima",
+    "ooui-toolbar-more": "Mais"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/pt.json b/resources/oojs-ui/i18n/pt.json
new file mode 100644 (file)
index 0000000..a4dba27
--- /dev/null
@@ -0,0 +1,19 @@
+{
+    "@metadata": {
+        "authors": [
+            "Cainamarques",
+            "Fúlvio",
+            "GoEThe",
+            "Hamilton Abreu",
+            "Helder.wiki",
+            "Jaideraf",
+            "Jdforrester",
+            "Luckas",
+            "Vitorvicentevalente"
+        ]
+    },
+    "ooui-dialog-action-close": "Fechar",
+    "ooui-outline-control-move-down": "Mover item para baixo",
+    "ooui-outline-control-move-up": "Mover item para cima",
+    "ooui-toolbar-more": "Mais"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/qqq.json b/resources/oojs-ui/i18n/qqq.json
new file mode 100644 (file)
index 0000000..78a70d9
--- /dev/null
@@ -0,0 +1,26 @@
+{
+    "@metadata": {
+        "authors": [
+            "Amire80",
+            "Beta16",
+            "Erik Moeller",
+            "Jdforrester",
+            "Lloffiwr",
+            "Mooeypoo",
+            "Mormegil",
+            "Nike",
+            "PoLuX124",
+            "Purodha",
+            "Raymond",
+            "Sagan",
+            "Sayak Sarkar",
+            "Shirayuki",
+            "Siebrand",
+            "Trevor Parscal"
+        ]
+    },
+    "ooui-dialog-action-close": "Label text for button to exit from dialog.\n\n{{Identical|Close}}",
+    "ooui-outline-control-move-down": "Tool tip for a button that moves items in a list down one place",
+    "ooui-outline-control-move-up": "Tool tip for a button that moves items in a list up one place",
+    "ooui-toolbar-more": "Label for the toolbar group that contains a list of all other available tools.\n{{Identical|More}}"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/qu.json b/resources/oojs-ui/i18n/qu.json
new file mode 100644 (file)
index 0000000..9a412f5
--- /dev/null
@@ -0,0 +1,11 @@
+{
+    "@metadata": {
+        "authors": [
+            "AlimanRuna"
+        ]
+    },
+    "ooui-dialog-action-close": "Wichq'ay",
+    "ooui-outline-control-move-down": "Qallawata uraykuchiy",
+    "ooui-outline-control-move-up": "Qallawata huqariy",
+    "ooui-toolbar-more": "Aswan"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/ro.json b/resources/oojs-ui/i18n/ro.json
new file mode 100644 (file)
index 0000000..861b2fe
--- /dev/null
@@ -0,0 +1,14 @@
+{
+    "@metadata": {
+        "authors": [
+            "AlimanRuna",
+            "Firilacroco",
+            "Minisarm",
+            "Stelistcristi"
+        ]
+    },
+    "ooui-dialog-action-close": "Închide",
+    "ooui-outline-control-move-down": "Mută elementul mai jos",
+    "ooui-outline-control-move-up": "Mută elementul mai sus",
+    "ooui-toolbar-more": "Mai mult"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/roa-tara.json b/resources/oojs-ui/i18n/roa-tara.json
new file mode 100644 (file)
index 0000000..c7699d6
--- /dev/null
@@ -0,0 +1,11 @@
+{
+    "@metadata": {
+        "authors": [
+            "Joetaras"
+        ]
+    },
+    "ooui-dialog-action-close": "Achiude",
+    "ooui-outline-control-move-down": "Spuèste 'a vôsce sotte",
+    "ooui-outline-control-move-up": "Spuèste 'a vôsce sus",
+    "ooui-toolbar-more": "De cchiù"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/ru.json b/resources/oojs-ui/i18n/ru.json
new file mode 100644 (file)
index 0000000..be7c6a5
--- /dev/null
@@ -0,0 +1,25 @@
+{
+    "@metadata": {
+        "authors": [
+            "Amire80",
+            "DR",
+            "Eugrus",
+            "Iluvatar",
+            "KPu3uC B Poccuu",
+            "Kalan",
+            "MaxBioHazard",
+            "NBS",
+            "Niklem",
+            "Okras",
+            "Ole Yves",
+            "Putnik",
+            "Sunpriat",
+            "Yury Katkov",
+            "Умар"
+        ]
+    },
+    "ooui-dialog-action-close": "Закрыть",
+    "ooui-outline-control-move-down": "Переместить элемент вниз",
+    "ooui-outline-control-move-up": "Переместить элемент вверх",
+    "ooui-toolbar-more": "Ещё"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/sah.json b/resources/oojs-ui/i18n/sah.json
new file mode 100644 (file)
index 0000000..9b3fcc8
--- /dev/null
@@ -0,0 +1,9 @@
+{
+    "@metadata": {
+        "authors": [
+            "Gazeb",
+            "HalanTul"
+        ]
+    },
+    "ooui-dialog-action-close": "Сап"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/scn.json b/resources/oojs-ui/i18n/scn.json
new file mode 100644 (file)
index 0000000..a699911
--- /dev/null
@@ -0,0 +1,13 @@
+{
+    "@metadata": {
+        "authors": [
+            "Gazeb",
+            "Gmelfi",
+            "HalanTul"
+        ]
+    },
+    "ooui-dialog-action-close": "Chiùi",
+    "ooui-outline-control-move-down": "Sposta di sutta",
+    "ooui-outline-control-move-up": "Sposta di supra",
+    "ooui-toolbar-more": "Àutri cosi"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/sh.json b/resources/oojs-ui/i18n/sh.json
new file mode 100644 (file)
index 0000000..5e29980
--- /dev/null
@@ -0,0 +1,10 @@
+{
+    "@metadata": {
+        "authors": [
+            "OC Ripper"
+        ]
+    },
+    "ooui-dialog-action-close": "Zatvori",
+    "ooui-outline-control-move-down": "Pomakni stavku dolje",
+    "ooui-outline-control-move-up": "Pomakni stavku gore"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/si.json b/resources/oojs-ui/i18n/si.json
new file mode 100644 (file)
index 0000000..cf7a9fd
--- /dev/null
@@ -0,0 +1,12 @@
+{
+    "@metadata": {
+        "authors": [
+            "Singhalawap",
+            "පසිඳු කාවින්ද",
+            "ශ්වෙත"
+        ]
+    },
+    "ooui-dialog-action-close": "නිමවන්න",
+    "ooui-outline-control-move-down": "අයිතමය පහලටදමන්න",
+    "ooui-outline-control-move-up": "අයිතමය ඉහලටදමන්න"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/sk.json b/resources/oojs-ui/i18n/sk.json
new file mode 100644 (file)
index 0000000..60b6f43
--- /dev/null
@@ -0,0 +1,12 @@
+{
+    "@metadata": {
+        "authors": [
+            "Mimarik",
+            "Teslaton"
+        ]
+    },
+    "ooui-dialog-action-close": "Zatvoriť",
+    "ooui-outline-control-move-down": "Posunúť položku nadol",
+    "ooui-outline-control-move-up": "Posunúť položku nahor",
+    "ooui-toolbar-more": "Viac"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/sl.json b/resources/oojs-ui/i18n/sl.json
new file mode 100644 (file)
index 0000000..d5bffd9
--- /dev/null
@@ -0,0 +1,14 @@
+{
+    "@metadata": {
+        "authors": [
+            "Dbc334",
+            "Eleassar",
+            "Pinky sl",
+            "Yerpo"
+        ]
+    },
+    "ooui-dialog-action-close": "Zapri",
+    "ooui-outline-control-move-down": "Prestavi predmet nižje",
+    "ooui-outline-control-move-up": "Prestavi predmet višje",
+    "ooui-toolbar-more": "Več"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/sq.json b/resources/oojs-ui/i18n/sq.json
new file mode 100644 (file)
index 0000000..424f1be
--- /dev/null
@@ -0,0 +1,11 @@
+{
+    "@metadata": {
+        "authors": [
+            "Euriditi"
+        ]
+    },
+    "ooui-dialog-action-close": "Mbylle",
+    "ooui-outline-control-move-down": "Zhvendose artikullin më poshtë",
+    "ooui-outline-control-move-up": "Zhvendose artikullin më lart",
+    "ooui-toolbar-more": "Më tepër..."
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/sr-ec.json b/resources/oojs-ui/i18n/sr-ec.json
new file mode 100644 (file)
index 0000000..973baec
--- /dev/null
@@ -0,0 +1,13 @@
+{
+    "@metadata": {
+        "authors": [
+            "Milicevic01",
+            "Nikola Smolenski",
+            "Милан Јелисавчић"
+        ]
+    },
+    "ooui-dialog-action-close": "Затвори",
+    "ooui-outline-control-move-down": "Премести ставку на доле",
+    "ooui-outline-control-move-up": "Премести ставку на горе",
+    "ooui-toolbar-more": "Више"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/sv.json b/resources/oojs-ui/i18n/sv.json
new file mode 100644 (file)
index 0000000..74d654b
--- /dev/null
@@ -0,0 +1,20 @@
+{
+    "@metadata": {
+        "authors": [
+            "Ainali",
+            "Haxpett",
+            "Jopparn",
+            "Knuckles",
+            "Magol",
+            "Milicevic01",
+            "Per",
+            "Sendelbach",
+            "Skalman",
+            "WikiPhoenix"
+        ]
+    },
+    "ooui-dialog-action-close": "Stäng",
+    "ooui-outline-control-move-down": "Flytta ned objekt",
+    "ooui-outline-control-move-up": "Flytta upp objekt",
+    "ooui-toolbar-more": "Mer"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/sw.json b/resources/oojs-ui/i18n/sw.json
new file mode 100644 (file)
index 0000000..1c61b06
--- /dev/null
@@ -0,0 +1,12 @@
+{
+    "@metadata": {
+        "authors": [
+            "Lloffiwr",
+            "Muddyb Blast Producer"
+        ]
+    },
+    "ooui-dialog-action-close": "Funga",
+    "ooui-outline-control-move-down": "Sogeza kipengee chini",
+    "ooui-outline-control-move-up": "Sogeza kipengee juu",
+    "ooui-toolbar-more": "Zaidi"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/ta.json b/resources/oojs-ui/i18n/ta.json
new file mode 100644 (file)
index 0000000..a9795fd
--- /dev/null
@@ -0,0 +1,11 @@
+{
+    "@metadata": {
+        "authors": [
+            "Jayarathina",
+            "Sank",
+            "Shanmugamp7",
+            "மதனாஹரன்"
+        ]
+    },
+    "ooui-dialog-action-close": "மூடுக"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/te.json b/resources/oojs-ui/i18n/te.json
new file mode 100644 (file)
index 0000000..a1f1285
--- /dev/null
@@ -0,0 +1,14 @@
+{
+    "@metadata": {
+        "authors": [
+            "Arjunaraoc",
+            "Jayarathina",
+            "Sank",
+            "Shanmugamp7",
+            "Veeven",
+            "Visdaviva",
+            "மதனாஹரன்"
+        ]
+    },
+    "ooui-dialog-action-close": "మూయి"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/th.json b/resources/oojs-ui/i18n/th.json
new file mode 100644 (file)
index 0000000..b7ee05a
--- /dev/null
@@ -0,0 +1,11 @@
+{
+    "@metadata": {
+        "authors": [
+            "Supasate",
+            "Taweetham"
+        ]
+    },
+    "ooui-dialog-action-close": "ปิด",
+    "ooui-outline-control-move-down": "เลื่อนรายการลง",
+    "ooui-outline-control-move-up": "ย้ายรายการขึ้น"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/tl.json b/resources/oojs-ui/i18n/tl.json
new file mode 100644 (file)
index 0000000..a073882
--- /dev/null
@@ -0,0 +1,12 @@
+{
+    "@metadata": {
+        "authors": [
+            "AnakngAraw",
+            "Sky Harbor"
+        ]
+    },
+    "ooui-dialog-action-close": "Isara",
+    "ooui-outline-control-move-down": "Ilipat ang aytem pababa",
+    "ooui-outline-control-move-up": "Ilipat ang aytem pataas",
+    "ooui-toolbar-more": "Marami pa"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/tr.json b/resources/oojs-ui/i18n/tr.json
new file mode 100644 (file)
index 0000000..94d34a2
--- /dev/null
@@ -0,0 +1,17 @@
+{
+    "@metadata": {
+        "authors": [
+            "Emperyan",
+            "Incelemeelemani",
+            "LuCKY",
+            "Maidis",
+            "Rapsar",
+            "Talha Samil Cakir",
+            "TurkishStyles"
+        ]
+    },
+    "ooui-dialog-action-close": "Kapat",
+    "ooui-outline-control-move-down": "Ögeyi aşağı taşı",
+    "ooui-outline-control-move-up": "Ögeyi yukarı taşı",
+    "ooui-toolbar-more": "Daha fazla"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/tt-cyrl.json b/resources/oojs-ui/i18n/tt-cyrl.json
new file mode 100644 (file)
index 0000000..1c0bd90
--- /dev/null
@@ -0,0 +1,10 @@
+{
+    "@metadata": {
+        "authors": [
+            "Ajdar"
+        ]
+    },
+    "ooui-dialog-action-close": "Ябу",
+    "ooui-outline-control-move-down": "Элементны аска күчерү",
+    "ooui-outline-control-move-up": "Элементны өскә күчерү"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/ug-arab.json b/resources/oojs-ui/i18n/ug-arab.json
new file mode 100644 (file)
index 0000000..efba086
--- /dev/null
@@ -0,0 +1,9 @@
+{
+    "@metadata": {
+        "authors": [
+            "Sahran",
+            "Tel'et",
+            "Tifinaghes"
+        ]
+    }
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/uk.json b/resources/oojs-ui/i18n/uk.json
new file mode 100644 (file)
index 0000000..9a47ad7
--- /dev/null
@@ -0,0 +1,24 @@
+{
+    "@metadata": {
+        "authors": [
+            "AS",
+            "Aced",
+            "Ahonc",
+            "Andriykopanytsia",
+            "Base",
+            "Perohanych",
+            "RLuts",
+            "Sahran",
+            "Sergento",
+            "Steve.rusyn",
+            "SteveR",
+            "Tel'et",
+            "Tifinaghes",
+            "Ата"
+        ]
+    },
+    "ooui-dialog-action-close": "Закрити",
+    "ooui-outline-control-move-down": "Перемістити елемент униз",
+    "ooui-outline-control-move-up": "Перемістити елемент вгору",
+    "ooui-toolbar-more": "Більше"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/uz.json b/resources/oojs-ui/i18n/uz.json
new file mode 100644 (file)
index 0000000..473fc75
--- /dev/null
@@ -0,0 +1,14 @@
+{
+    "@metadata": {
+        "authors": [
+            "CoderSI",
+            "Noor2020",
+            "Sociologist",
+            "පසිඳු කාවින්ද"
+        ]
+    },
+    "ooui-dialog-action-close": "Yopish",
+    "ooui-outline-control-move-down": "Elementni pastga koʻchirish",
+    "ooui-outline-control-move-up": "Elementni yuqoriga koʻchirish",
+    "ooui-toolbar-more": "Yana"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/vec.json b/resources/oojs-ui/i18n/vec.json
new file mode 100644 (file)
index 0000000..01833f7
--- /dev/null
@@ -0,0 +1,12 @@
+{
+    "@metadata": {
+        "authors": [
+            "Candalua",
+            "GatoSelvadego"
+        ]
+    },
+    "ooui-dialog-action-close": "Sara",
+    "ooui-outline-control-move-down": "Sposta in baso",
+    "ooui-outline-control-move-up": "Sposta in sima",
+    "ooui-toolbar-more": "Altro"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/vi.json b/resources/oojs-ui/i18n/vi.json
new file mode 100644 (file)
index 0000000..b545ce6
--- /dev/null
@@ -0,0 +1,13 @@
+{
+    "@metadata": {
+        "authors": [
+            "Cheers!",
+            "Jdforrester",
+            "Minh Nguyen"
+        ]
+    },
+    "ooui-dialog-action-close": "Đóng",
+    "ooui-outline-control-move-down": "Chuyển mục xuống",
+    "ooui-outline-control-move-up": "Chuyển mục lên",
+    "ooui-toolbar-more": "Thêm"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/vo.json b/resources/oojs-ui/i18n/vo.json
new file mode 100644 (file)
index 0000000..2ed7e2f
--- /dev/null
@@ -0,0 +1,9 @@
+{
+    "@metadata": {
+        "authors": [
+            "Malafaya"
+        ]
+    },
+    "ooui-dialog-action-close": "Färmükön",
+    "ooui-toolbar-more": "Pluikos"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/wuu.json b/resources/oojs-ui/i18n/wuu.json
new file mode 100644 (file)
index 0000000..72aa48b
--- /dev/null
@@ -0,0 +1,9 @@
+{
+    "@metadata": {
+        "authors": [
+            "Malafaya",
+            "十弌"
+        ]
+    },
+    "ooui-toolbar-more": "還多"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/yi.json b/resources/oojs-ui/i18n/yi.json
new file mode 100644 (file)
index 0000000..ab5c510
--- /dev/null
@@ -0,0 +1,13 @@
+{
+    "@metadata": {
+        "authors": [
+            "Malafaya",
+            "פוילישער",
+            "十弌"
+        ]
+    },
+    "ooui-dialog-action-close": "שליסן",
+    "ooui-outline-control-move-down": "רוקן עלעמענט אראפ",
+    "ooui-outline-control-move-up": "רוקן עלעמענט ארויף",
+    "ooui-toolbar-more": "נאך"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/yo.json b/resources/oojs-ui/i18n/yo.json
new file mode 100644 (file)
index 0000000..f71d3dd
--- /dev/null
@@ -0,0 +1,11 @@
+{
+    "@metadata": {
+        "authors": [
+            "Demmy"
+        ]
+    },
+    "ooui-dialog-action-close": "Ìpadé",
+    "ooui-outline-control-move-down": "Sún onítòún sí sàlẹ̀",
+    "ooui-outline-control-move-up": "Sún onítòún s'ókè",
+    "ooui-toolbar-more": "Míràn"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/zh-hans.json b/resources/oojs-ui/i18n/zh-hans.json
new file mode 100644 (file)
index 0000000..46cbae3
--- /dev/null
@@ -0,0 +1,25 @@
+{
+    "@metadata": {
+        "authors": [
+            "Anakmalaysia",
+            "Bencmq",
+            "Demmy",
+            "Hydra",
+            "Hzy980512",
+            "Liangent",
+            "Liuxinyu970226",
+            "Qiyue2001",
+            "Shirayuki",
+            "Shizhao",
+            "TianyinLee",
+            "Xiaomingyan",
+            "Yfdyh000",
+            "Zhangjintao",
+            "乌拉跨氪"
+        ]
+    },
+    "ooui-dialog-action-close": "关闭",
+    "ooui-outline-control-move-down": "下移项",
+    "ooui-outline-control-move-up": "上移项",
+    "ooui-toolbar-more": "更多"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/zh-hant.json b/resources/oojs-ui/i18n/zh-hant.json
new file mode 100644 (file)
index 0000000..9aace2f
--- /dev/null
@@ -0,0 +1,22 @@
+{
+    "@metadata": {
+        "authors": [
+            "Anakmalaysia",
+            "Ch.Andrew",
+            "Hydra",
+            "Justincheng12345",
+            "Liflon",
+            "Liuxinyu970226",
+            "Qiyue2001",
+            "Radish10cm",
+            "Shirayuki",
+            "Simon Shek",
+            "Spring Roll Conan",
+            "Waihorace"
+        ]
+    },
+    "ooui-dialog-action-close": "關閉",
+    "ooui-outline-control-move-down": "向下移項",
+    "ooui-outline-control-move-up": "向上移項",
+    "ooui-toolbar-more": "更多"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/zh-hk.json b/resources/oojs-ui/i18n/zh-hk.json
new file mode 100644 (file)
index 0000000..60e8fbd
--- /dev/null
@@ -0,0 +1,4 @@
+{
+    "@metadata": [],
+    "ooui-dialog-action-close": "關閉"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/i18n/zh-tw.json b/resources/oojs-ui/i18n/zh-tw.json
new file mode 100644 (file)
index 0000000..f7987e5
--- /dev/null
@@ -0,0 +1,7 @@
+{
+    "@metadata": [],
+    "ooui-dialog-action-close": "關閉",
+    "ooui-outline-control-move-down": "向下移",
+    "ooui-outline-control-move-up": "向上移",
+    "ooui-toolbar-more": "更多"
+}
\ No newline at end of file
diff --git a/resources/oojs-ui/images/fade-down.png b/resources/oojs-ui/images/fade-down.png
new file mode 100644 (file)
index 0000000..50c7931
Binary files /dev/null and b/resources/oojs-ui/images/fade-down.png differ
diff --git a/resources/oojs-ui/images/fade-up.png b/resources/oojs-ui/images/fade-up.png
new file mode 100644 (file)
index 0000000..7a0cb87
Binary files /dev/null and b/resources/oojs-ui/images/fade-up.png differ
diff --git a/resources/oojs-ui/images/icons/accept.png b/resources/oojs-ui/images/icons/accept.png
new file mode 100644 (file)
index 0000000..1075110
Binary files /dev/null and b/resources/oojs-ui/images/icons/accept.png differ
diff --git a/resources/oojs-ui/images/icons/accept.svg b/resources/oojs-ui/images/icons/accept.svg
new file mode 100644 (file)
index 0000000..df78186
--- /dev/null
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px"
+        height="24px" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
+<g id="apply" style="opacity:0.75;">
+       <polygon id="check" style="fill-rule:evenodd;clip-rule:evenodd;" points="19.062,5.139 17.418,4 8.867,16.357 5.413,12.903 4,14.316 9.021,19.338"/>
+</g>
+</svg>
diff --git a/resources/oojs-ui/images/icons/add-item.png b/resources/oojs-ui/images/icons/add-item.png
new file mode 100644 (file)
index 0000000..aa36cd0
Binary files /dev/null and b/resources/oojs-ui/images/icons/add-item.png differ
diff --git a/resources/oojs-ui/images/icons/add-item.svg b/resources/oojs-ui/images/icons/add-item.svg
new file mode 100644 (file)
index 0000000..ff95399
--- /dev/null
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24" height="24" viewBox="0, 0, 24, 24">
+  <g id="add-item">
+    <path d="M13,8 L11,8 L11,11 L8,11 L8,13 L11,13 L11,16 L13,16 L13,13 L16,13 L16,11 L13,11 z" fill="#000000"/>
+  </g>
+  <defs/>
+</svg>
diff --git a/resources/oojs-ui/images/icons/advanced.png b/resources/oojs-ui/images/icons/advanced.png
new file mode 100644 (file)
index 0000000..7f5ada5
Binary files /dev/null and b/resources/oojs-ui/images/icons/advanced.png differ
diff --git a/resources/oojs-ui/images/icons/advanced.svg b/resources/oojs-ui/images/icons/advanced.svg
new file mode 100644 (file)
index 0000000..3e87cab
--- /dev/null
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px"
+        height="24px" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
+<g id="settings" style="opacity:0.75;">
+       <path id="gear" style="fill-rule:evenodd;clip-rule:evenodd;" d="M20.869,13.476C20.948,12.994,21,12.504,21,12
+               s-0.052-0.994-0.131-1.476l-2.463-0.259c-0.149-0.556-0.367-1.082-0.648-1.57l1.558-1.924c-0.576-0.806-1.281-1.511-2.087-2.087
+               l-1.924,1.558c-0.488-0.281-1.015-0.499-1.57-0.648l-0.259-2.463C12.994,3.052,12.504,3,12,3s-0.994,0.052-1.476,0.131
+               l-0.259,2.463C9.71,5.743,9.184,5.961,8.695,6.242L6.771,4.685C5.966,5.261,5.261,5.966,4.685,6.771l1.558,1.924
+               c-0.281,0.488-0.499,1.015-0.648,1.57l-2.463,0.259C3.052,11.006,3,11.496,3,12s0.052,0.994,0.131,1.476l2.463,0.259
+               c0.149,0.556,0.367,1.082,0.648,1.57l-1.558,1.924c0.576,0.806,1.281,1.511,2.087,2.087l1.924-1.558
+               c0.488,0.281,1.015,0.499,1.57,0.648l0.259,2.463C11.006,20.948,11.496,21,12,21s0.994-0.052,1.476-0.131l0.259-2.463
+               c0.556-0.149,1.082-0.367,1.57-0.648l1.924,1.558c0.806-0.576,1.511-1.281,2.087-2.087l-1.558-1.924
+               c0.281-0.488,0.499-1.015,0.648-1.57L20.869,13.476z M12,15.998c-2.209,0-3.998-1.789-3.998-3.998S9.791,8.002,12,8.002
+               S15.998,9.791,15.998,12S14.209,15.998,12,15.998z"/>
+</g>
+</svg>
diff --git a/resources/oojs-ui/images/icons/alert.png b/resources/oojs-ui/images/icons/alert.png
new file mode 100644 (file)
index 0000000..992ea2a
Binary files /dev/null and b/resources/oojs-ui/images/icons/alert.png differ
diff --git a/resources/oojs-ui/images/icons/alert.svg b/resources/oojs-ui/images/icons/alert.svg
new file mode 100644 (file)
index 0000000..886a7c0
--- /dev/null
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px"
+        height="24px" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
+<g id="alert" style="opacity:0.75;">
+       <rect id="point" x="11" y="16" style="fill-rule:evenodd;clip-rule:evenodd;" width="2" height="2"/>
+       <polygon id="stroke" style="fill-rule:evenodd;clip-rule:evenodd;" points="13.516,10 10.516,10 11,15 13,15"/>
+       <path id="triangle" d="M12.017,5.974L19.536,19H4.496L12.017,5.974 M12.017,3.5c-0.544,0-1.088,0.357-1.5,1.071L2.532,18.402 C1.707,19.831,2.382,21,4.032,21H20c1.65,0,2.325-1.169,1.5-2.599L13.517,4.572C13.104,3.857,12.561,3.5,12.017,3.5L12.017,3.5z"/>
+</g>
+</svg>
diff --git a/resources/oojs-ui/images/icons/arched-arrow-ltr.png b/resources/oojs-ui/images/icons/arched-arrow-ltr.png
new file mode 100644 (file)
index 0000000..5db1c4d
Binary files /dev/null and b/resources/oojs-ui/images/icons/arched-arrow-ltr.png differ
diff --git a/resources/oojs-ui/images/icons/arched-arrow-ltr.svg b/resources/oojs-ui/images/icons/arched-arrow-ltr.svg
new file mode 100644 (file)
index 0000000..5b343a5
--- /dev/null
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px"
+        height="24px" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
+<g id="arched-arrow-ltr" style="opacity:0.75;">
+       <path id="arrow" style="fill-rule:evenodd;clip-rule:evenodd;" d="M19.925,14.937l-2.391-6.901l-1.48,2.329 c-0.964-0.845-2.699-1.85-5.513-1.823c-4.887,0.046-6.524,4.244-6.524,4.244s2.753-2.639,6.925-1.949 c1.729,0.286,3.007,1.206,3.675,1.791l-1.474,2.319L19.925,14.937z"/>
+</g>
+</svg>
diff --git a/resources/oojs-ui/images/icons/arched-arrow-rtl.png b/resources/oojs-ui/images/icons/arched-arrow-rtl.png
new file mode 100644 (file)
index 0000000..7931971
Binary files /dev/null and b/resources/oojs-ui/images/icons/arched-arrow-rtl.png differ
diff --git a/resources/oojs-ui/images/icons/arched-arrow-rtl.svg b/resources/oojs-ui/images/icons/arched-arrow-rtl.svg
new file mode 100644 (file)
index 0000000..bb5f10e
--- /dev/null
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px"
+        height="24px" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
+<g id="arched-arrow-rtl" style="opacity:0.75;">
+       <path id="arrow" style="fill-rule:evenodd;clip-rule:evenodd;" d="M13.401,8.542c-2.814-0.027-4.549,0.978-5.513,1.823 l-1.48-2.329l-2.391,6.901l6.782,0.009l-1.474-2.319c0.668-0.584,1.945-1.504,3.675-1.791c4.172-0.69,6.925,1.949,6.925,1.949 S18.288,8.588,13.401,8.542z"/>
+</g>
+</svg>
diff --git a/resources/oojs-ui/images/icons/check.png b/resources/oojs-ui/images/icons/check.png
new file mode 100644 (file)
index 0000000..82c3cb4
Binary files /dev/null and b/resources/oojs-ui/images/icons/check.png differ
diff --git a/resources/oojs-ui/images/icons/check.svg b/resources/oojs-ui/images/icons/check.svg
new file mode 100644 (file)
index 0000000..e67cd6c
--- /dev/null
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24" height="24" viewBox="0, 0, 24, 24">
+  <g id="check">
+    <path d="M7.105,13.473 L8.527,12.05 L10.428,13.952 L15.238,7 L16.895,8.148 L10.635,17 z" fill="#000000"/>
+  </g>
+  <defs/>
+</svg>
diff --git a/resources/oojs-ui/images/icons/clear.png b/resources/oojs-ui/images/icons/clear.png
new file mode 100644 (file)
index 0000000..697dd62
Binary files /dev/null and b/resources/oojs-ui/images/icons/clear.png differ
diff --git a/resources/oojs-ui/images/icons/clear.svg b/resources/oojs-ui/images/icons/clear.svg
new file mode 100644 (file)
index 0000000..d83eb02
--- /dev/null
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px"
+        height="24px" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
+<g id="clear" style="opacity:0.75;">
+       <path id="circle_with_strike" style="fill-rule:evenodd;clip-rule:evenodd;" d="M11.999,5.022c-3.853,0-6.977,3.124-6.977,6.978 c0,3.853,3.124,6.978,6.977,6.978c3.854,0,6.979-3.125,6.979-6.978C18.978,8.146,15.853,5.022,11.999,5.022z M6.886,12 c0-1.092,0.572-3.25,0.93-2.929l7.113,7.113c0.488,0.525-1.837,0.931-2.93,0.931C9.174,17.114,6.886,14.824,6.886,12z M16.184,14.929L9.07,7.816c-0.445-0.483,1.837-0.931,2.929-0.931c2.827,0,5.115,2.289,5.115,5.114 C17.114,13.092,16.75,15.542,16.184,14.929z"/>
+</g>
+</svg>
diff --git a/resources/oojs-ui/images/icons/close.png b/resources/oojs-ui/images/icons/close.png
new file mode 100644 (file)
index 0000000..f7eed9f
Binary files /dev/null and b/resources/oojs-ui/images/icons/close.png differ
diff --git a/resources/oojs-ui/images/icons/close.svg b/resources/oojs-ui/images/icons/close.svg
new file mode 100644 (file)
index 0000000..a0118c2
--- /dev/null
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px"
+        height="24px" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
+<g id="close" style="opacity:0.75;">
+       <polygon id="x" style="fill-rule:evenodd;clip-rule:evenodd;" points="18.717,6.697 17.303,5.283 12,10.586 6.697,5.283 5.283,6.697 10.586,12 5.283,17.303 6.697,18.717 12,13.414 17.303,18.717 18.717,17.303 13.414,12            "/>
+</g>
+</svg>
diff --git a/resources/oojs-ui/images/icons/code.png b/resources/oojs-ui/images/icons/code.png
new file mode 100644 (file)
index 0000000..a5ebdbf
Binary files /dev/null and b/resources/oojs-ui/images/icons/code.png differ
diff --git a/resources/oojs-ui/images/icons/code.svg b/resources/oojs-ui/images/icons/code.svg
new file mode 100644 (file)
index 0000000..6f1ed53
--- /dev/null
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+        width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
+<g id="code" opacity="0.75">
+       <path id="left-bracket" d="M4,12v-1h1c1,0,1,0,1-1V7.614C6,7.1,6.024,6.718,6.073,6.472C6.127,6.22,6.212,6.009,6.33,5.839
+               C6.534,5.56,6.803,5.364,7.138,5.255C7.473,5.14,8.01,5,8.973,5H10v1H9.248c-0.457,0-0.77,0.191-0.936,0.408
+               C8.145,6.623,8,6.853,8,7.476v1.857c0,0.729-0.041,1.18-0.244,1.493c-0.2,0.307-0.562,0.529-1.09,0.667
+               c0.535,0.155,0.9,0.385,1.096,0.688C7.961,12.484,8,12.938,8,13.665v1.862c0,0.619,0.145,0.848,0.312,1.062
+               c0.166,0.22,0.479,0.407,0.936,0.407L10,17l0,0v1H8.973c-0.963,0-1.5-0.133-1.835-0.248c-0.335-0.109-0.604-0.307-0.808-0.591
+               c-0.118-0.165-0.203-0.374-0.257-0.625C6.024,16.283,6,15.9,6,15.387V13c0-1,0-1-1-1H4z"/>
+       <use transform="matrix(-1,0,0,1,24,0)" id="right-bracket" x="0" y="0" width="24" height="24" xlink:href="#left-bracket" />
+</g>
+</svg>
diff --git a/resources/oojs-ui/images/icons/collapse.png b/resources/oojs-ui/images/icons/collapse.png
new file mode 100644 (file)
index 0000000..38b796f
Binary files /dev/null and b/resources/oojs-ui/images/icons/collapse.png differ
diff --git a/resources/oojs-ui/images/icons/collapse.svg b/resources/oojs-ui/images/icons/collapse.svg
new file mode 100644 (file)
index 0000000..a89cebf
--- /dev/null
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px"
+        height="24px" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
+<g id="collapse" style="opacity:0.75;">
+       <polygon id="arrow" style="fill-rule:evenodd;clip-rule:evenodd;" points="6.697,15.714 12,10.412 17.303,15.714 18.717,14.3 12,7.583 5.283,14.3"/>
+</g>
+</svg>
diff --git a/resources/oojs-ui/images/icons/comment.png b/resources/oojs-ui/images/icons/comment.png
new file mode 100644 (file)
index 0000000..9546455
Binary files /dev/null and b/resources/oojs-ui/images/icons/comment.png differ
diff --git a/resources/oojs-ui/images/icons/comment.svg b/resources/oojs-ui/images/icons/comment.svg
new file mode 100644 (file)
index 0000000..e052935
--- /dev/null
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px"
+        height="24px" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
+<g id="comment" style="opacity:0.75;">
+       <path id="speech_bubble" style="fill-rule:evenodd;clip-rule:evenodd;" d="M15,6H9C7.343,6,6,7.344,6,9v4c0,1.656,1.343,3,3,3v3 l3-3h3c1.657,0,3-1.344,3-3V9C18,7.344,16.657,6,15,6z"/>
+</g>
+</svg>
diff --git a/resources/oojs-ui/images/icons/expand.png b/resources/oojs-ui/images/icons/expand.png
new file mode 100644 (file)
index 0000000..e90aca1
Binary files /dev/null and b/resources/oojs-ui/images/icons/expand.png differ
diff --git a/resources/oojs-ui/images/icons/expand.svg b/resources/oojs-ui/images/icons/expand.svg
new file mode 100644 (file)
index 0000000..b542f5f
--- /dev/null
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px"
+        height="24px" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
+<g id="expand" style="opacity:0.75;">
+       <polygon id="arrow" style="fill-rule:evenodd;clip-rule:evenodd;" points="17.303,8.283 12,13.586 6.697,8.283 5.283,9.697 12,16.414 18.717,9.697"/>
+</g>
+</svg>
diff --git a/resources/oojs-ui/images/icons/help.png b/resources/oojs-ui/images/icons/help.png
new file mode 100644 (file)
index 0000000..dca745b
Binary files /dev/null and b/resources/oojs-ui/images/icons/help.png differ
diff --git a/resources/oojs-ui/images/icons/help.svg b/resources/oojs-ui/images/icons/help.svg
new file mode 100644 (file)
index 0000000..c68bdda
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px"
+        height="24px" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
+<g id="help" style="opacity:0.75;">
+       <path id="circle" style="fill-rule:evenodd;clip-rule:evenodd;" d="M12.001,2.085c-5.478,0-9.916,4.438-9.916,9.916 c0,5.476,4.438,9.914,9.916,9.914c5.476,0,9.914-4.438,9.914-9.914C21.915,6.523,17.477,2.085,12.001,2.085z M12.002,20.085 c-4.465,0-8.084-3.619-8.084-8.083c0-4.465,3.619-8.084,8.084-8.084c4.464,0,8.083,3.619,8.083,8.084 C20.085,16.466,16.466,20.085,12.002,20.085z"/>
+       <g id="question_mark">
+               <path id="top" style="fill-rule:evenodd;clip-rule:evenodd;" d="M11.766,6.688c-2.5,0-3.219,2.188-3.219,2.188l1.411,0.854 c0,0,0.298-0.791,0.901-1.229c0.516-0.375,1.625-0.625,2.219,0.125c0.701,0.885-0.17,1.587-1.078,2.719 C11.047,12.531,11,15,11,15h1.969c0,0,0.135-2.318,1.041-3.381c0.603-0.707,1.443-1.338,1.443-2.494S14.266,6.688,11.766,6.688z"/>
+               <rect id="bottom" x="11" y="16" style="fill-rule:evenodd;clip-rule:evenodd;" width="2" height="2"/>
+       </g>
+</g>
+</svg>
diff --git a/resources/oojs-ui/images/icons/history.png b/resources/oojs-ui/images/icons/history.png
new file mode 100644 (file)
index 0000000..c049931
Binary files /dev/null and b/resources/oojs-ui/images/icons/history.png differ
diff --git a/resources/oojs-ui/images/icons/history.svg b/resources/oojs-ui/images/icons/history.svg
new file mode 100644 (file)
index 0000000..40c0ae3
--- /dev/null
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px"
+        height="24px" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
+<g id="history" style="opacity:0.75;">
+       <path id="clock_hands" style="fill-rule:evenodd;clip-rule:evenodd;" d="M17.26,15.076c0,0-2.385-1.935-4.005-3.062 c0.72-2.397,1.702-6.559,1.702-6.559s-4.35,5.363-4.877,6.699c-0.463,1.168,1.459,2.209,2.346,1.678 C14.326,14.383,17.26,15.076,17.26,15.076z"/>
+       <path id="arrow" style="fill-rule:evenodd;clip-rule:evenodd;" d="M12.086,2.085c-5.478,0-9.916,4.438-9.916,9.916 c0,1.783,0.476,3.454,1.301,4.898l-2.223,2.04h5.688v-5.219l-2.066,1.896c-0.55-1.088-0.866-2.312-0.866-3.615 c0-4.465,3.619-8.084,8.084-8.084c4.464,0,8.083,3.619,8.083,8.084c0,4.464-3.619,8.083-8.083,8.083 c-1.145,0-2.228-0.247-3.213-0.678l-0.833,1.634c1.235,0.557,2.602,0.874,4.045,0.874c5.476,0,9.914-4.438,9.914-9.914 C22,6.523,17.562,2.085,12.086,2.085z"/>
+</g>
+</svg>
diff --git a/resources/oojs-ui/images/icons/link.png b/resources/oojs-ui/images/icons/link.png
new file mode 100644 (file)
index 0000000..7dfa268
Binary files /dev/null and b/resources/oojs-ui/images/icons/link.png differ
diff --git a/resources/oojs-ui/images/icons/link.svg b/resources/oojs-ui/images/icons/link.svg
new file mode 100644 (file)
index 0000000..dadf69c
--- /dev/null
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px"
+        height="24px" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
+<g id="link" style="opacity:0.75;">
+       <path id="right" d="M19.188,12.001c0,1.1-0.891,2.015-1.988,2.015l-4.195-0.015C13.543,15.089,13.968,16,15.002,16h3
+               C19.658,16,21,13.657,21,12s-1.342-4-2.998-4h-3c-1.034,0-1.459,0.911-1.998,1.999l4.195-0.015
+               C18.297,9.984,19.188,10.901,19.188,12.001z"/>
+       <path id="center" d="M8,12c0,0.535,0.42,1,0.938,1h6.109c0.518,0,0.938-0.465,0.938-1c0-0.534-0.42-1-0.938-1H8.938
+               C8.42,11,8,11.466,8,12z"/>
+       <path id="left" d="M4.816,11.999c0-1.1,0.891-2.015,1.988-2.015L11,9.999C10.461,8.911,10.036,8,9.002,8h-3
+               c-1.656,0-2.998,2.343-2.998,4s1.342,4,2.998,4h3c1.034,0,1.459-0.911,1.998-1.999l-4.195,0.015
+               C5.707,14.016,4.816,13.099,4.816,11.999z"/>
+</g>
+</svg>
diff --git a/resources/oojs-ui/images/icons/menu.png b/resources/oojs-ui/images/icons/menu.png
new file mode 100644 (file)
index 0000000..b5ac60f
Binary files /dev/null and b/resources/oojs-ui/images/icons/menu.png differ
diff --git a/resources/oojs-ui/images/icons/menu.svg b/resources/oojs-ui/images/icons/menu.svg
new file mode 100644 (file)
index 0000000..657fab2
--- /dev/null
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px"
+        height="24px" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
+<g id="menu" style="opacity:0.75;">
+       <path id="lines" d="M6,15h12c0.553,0,1,0.447,1,1v1c0,0.553-0.447,1-1,1H6c-0.553,0-1-0.447-1-1v-1C5,15.447,5.447,15,6,15z M5,11v1
+               c0,0.553,0.447,1,1,1h12c0.553,0,1-0.447,1-1v-1c0-0.553-0.447-1-1-1H6C5.447,10,5,10.447,5,11z M5,6v1c0,0.553,0.447,1,1,1h12
+               c0.553,0,1-0.447,1-1V6c0-0.553-0.447-1-1-1H6C5.447,5,5,5.447,5,6z"/>
+</g>
+</svg>
diff --git a/resources/oojs-ui/images/icons/move-ltr.png b/resources/oojs-ui/images/icons/move-ltr.png
new file mode 100644 (file)
index 0000000..ded5f05
Binary files /dev/null and b/resources/oojs-ui/images/icons/move-ltr.png differ
diff --git a/resources/oojs-ui/images/icons/move-ltr.svg b/resources/oojs-ui/images/icons/move-ltr.svg
new file mode 100644 (file)
index 0000000..a378a5d
--- /dev/null
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px"
+        height="24px" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
+<g id="move-ltr" style="opacity:0.75;">
+       <polygon id="arrow" style="fill-rule:evenodd;clip-rule:evenodd;" points="8.935,7.181 14.237,12.483 8.935,17.786
+               10.349,19.2 17.065,12.483 10.349,5.767"/>
+</g>
+</svg>
diff --git a/resources/oojs-ui/images/icons/move-rtl.png b/resources/oojs-ui/images/icons/move-rtl.png
new file mode 100644 (file)
index 0000000..fc6e62d
Binary files /dev/null and b/resources/oojs-ui/images/icons/move-rtl.png differ
diff --git a/resources/oojs-ui/images/icons/move-rtl.svg b/resources/oojs-ui/images/icons/move-rtl.svg
new file mode 100644 (file)
index 0000000..c0b334b
--- /dev/null
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px"
+        height="24px" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
+<g id="move-rtl" style="opacity:0.75;">
+       <polygon id="arrow_9_" style="fill-rule:evenodd;clip-rule:evenodd;" points="15.065,17.786 9.763,12.483 15.065,7.181
+               13.651,5.767 6.935,12.483 13.651,19.2"/>
+</g>
+</svg>
diff --git a/resources/oojs-ui/images/icons/picture.png b/resources/oojs-ui/images/icons/picture.png
new file mode 100644 (file)
index 0000000..faf8af9
Binary files /dev/null and b/resources/oojs-ui/images/icons/picture.png differ
diff --git a/resources/oojs-ui/images/icons/picture.svg b/resources/oojs-ui/images/icons/picture.svg
new file mode 100644 (file)
index 0000000..078ce10
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px"
+        height="24px" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
+<g id="picture" style="opacity:0.75;">
+       <path id="frame" style="fill-rule:evenodd;clip-rule:evenodd;" d="M18,4H6C4,3.993,3,4.993,3,6.993L3.014,16C3,18,4,18.988,6,19h12
+               c2-0.012,2.994-1,3-3.006V6.993C20.994,4.993,20,3.993,18,4z M19,17H5V6h14V17z"/>
+       <polygon id="mountains" style="fill-rule:evenodd;clip-rule:evenodd;" points="6,13.5 9.5,10 11.828,12.312 10.516,13.406
+               11.391,14.438 15.5,11 18,13 18,16 6,16"/>
+       <polygon id="sky" style="fill-rule:evenodd;clip-rule:evenodd;" points="6,12 9.516,7.844 12.562,11.016 15.5,9 18,11 18,7 6,7"/>
+</g>
+</svg>
diff --git a/resources/oojs-ui/images/icons/remove-item.png b/resources/oojs-ui/images/icons/remove-item.png
new file mode 100644 (file)
index 0000000..2f11db3
Binary files /dev/null and b/resources/oojs-ui/images/icons/remove-item.png differ
diff --git a/resources/oojs-ui/images/icons/remove-item.svg b/resources/oojs-ui/images/icons/remove-item.svg
new file mode 100644 (file)
index 0000000..b95e7d3
--- /dev/null
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24" height="24" viewBox="0, 0, 24, 24">
+  <g id="remove-item">
+    <path d="M8,11 L16,11 L16,13 L8,13 z" fill="#000000"/>
+  </g>
+  <defs/>
+</svg>
diff --git a/resources/oojs-ui/images/icons/remove.png b/resources/oojs-ui/images/icons/remove.png
new file mode 100644 (file)
index 0000000..d7e116c
Binary files /dev/null and b/resources/oojs-ui/images/icons/remove.png differ
diff --git a/resources/oojs-ui/images/icons/remove.svg b/resources/oojs-ui/images/icons/remove.svg
new file mode 100644 (file)
index 0000000..17c8d39
--- /dev/null
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px"
+        height="24px" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
+<g id="remove" style="opacity:0.75;">
+       <path id="trash_can" style="fill-rule:evenodd;clip-rule:evenodd;" d="M12,10h-1v6h1V10z M10,10H9v6h1V10z M14,10h-1v6h1V10z
+                M14,6V5H9v1H6v3h1v7.966l1,1.031v-0.074V18h6.984L15,17.982v0.015l1-1.031V9h1V6H14z M15,17H8V9h7V17z M16,8H7V7h9V8z"/>
+</g>
+</svg>
diff --git a/resources/oojs-ui/images/icons/search.png b/resources/oojs-ui/images/icons/search.png
new file mode 100644 (file)
index 0000000..df29792
Binary files /dev/null and b/resources/oojs-ui/images/icons/search.png differ
diff --git a/resources/oojs-ui/images/icons/search.svg b/resources/oojs-ui/images/icons/search.svg
new file mode 100644 (file)
index 0000000..37feda4
--- /dev/null
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px"
+        height="24px" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
+<g id="search" style="opacity:0.75;">
+       <path id="magnifying_glass" d="M16.021,15.96l-2.374-2.375c-0.048-0.047-0.105-0.079-0.169-0.099c0.403-0.566,0.643-1.26,0.643-2.009
+               C14.12,9.557,12.563,8,10.644,8c-1.921,0-3.478,1.557-3.478,3.478c0,1.92,1.557,3.477,3.478,3.477c0.749,0,1.442-0.239,2.01-0.643
+               c0.019,0.063,0.051,0.121,0.098,0.169l2.375,2.374c0.19,0.189,0.543,0.143,0.79-0.104S16.21,16.15,16.021,15.96z M10.644,13.69
+               c-1.221,0-2.213-0.991-2.213-2.213c0-1.221,0.992-2.213,2.213-2.213c1.222,0,2.213,0.992,2.213,2.213
+               C12.856,12.699,11.865,13.69,10.644,13.69z"/>
+</g>
+</svg>
diff --git a/resources/oojs-ui/images/icons/settings.png b/resources/oojs-ui/images/icons/settings.png
new file mode 100644 (file)
index 0000000..b1b35e9
Binary files /dev/null and b/resources/oojs-ui/images/icons/settings.png differ
diff --git a/resources/oojs-ui/images/icons/settings.svg b/resources/oojs-ui/images/icons/settings.svg
new file mode 100644 (file)
index 0000000..1464a79
--- /dev/null
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24" height="24" viewBox="0, 0, 24, 24">
+  <g id="settings" opacity="0.75">
+    <path d="M3,4 L6,4 L6,6 L3,6 z" fill="#000000"/>
+    <path d="M12,4 L21,4 L21,6 L12,6 z" fill="#000000"/>
+    <path d="M8,3 L10,3 C10.552,3 11,3.448 11,4 L11,6 C11,6.552 10.552,7 10,7 L8,7 C7.448,7 7,6.552 7,6 L7,4 C7,3.448 7.448,3 8,3 z" fill="#000000"/>
+    <path d="M3,11 L12,11 L12,13 L3,13 z" fill="#000000"/>
+    <path d="M18,11 L21,11 L21,13 L18,13 z" fill="#000000"/>
+    <path d="M14,10 L16,10 C16.552,10 17,10.448 17,11 L17,13 C17,13.552 16.552,14 16,14 L14,14 C13.448,14 13,13.552 13,13 L13,11 C13,10.448 13.448,10 14,10 z" fill="#000000"/>
+    <path d="M3,18 L9,18 L9,20 L3,20 z" fill="#000000"/>
+    <path d="M15,18 L21,18 L21,20 L15,20 z" fill="#000000"/>
+    <path d="M11,17 L13,17 C13.552,17 14,17.448 14,18 L14,20 C14,20.552 13.552,21 13,21 L11,21 C10.448,21 10,20.552 10,20 L10,18 C10,17.448 10.448,17 11,17 z" fill="#000000"/>
+  </g>
+  <defs/>
+</svg>
diff --git a/resources/oojs-ui/images/icons/tag.png b/resources/oojs-ui/images/icons/tag.png
new file mode 100644 (file)
index 0000000..722f4d7
Binary files /dev/null and b/resources/oojs-ui/images/icons/tag.png differ
diff --git a/resources/oojs-ui/images/icons/tag.svg b/resources/oojs-ui/images/icons/tag.svg
new file mode 100644 (file)
index 0000000..d21e5e3
--- /dev/null
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px"
+        height="24px" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
+<g id="tag" style="opacity:0.75;">
+       <path d="M18.748,11.717c0.389,0.389,0.389,1.025,0,1.414l-4.949,4.95c-0.389,0.389-1.025,0.389-1.414,0l-6.01-6.01
+               c-0.389-0.389-0.707-1.157-0.707-1.707L5.667,6c0-0.55,0.45-1,1-1h4.364c0.55,0,1.318,0.318,1.707,0.707L18.748,11.717z
+                M8.104,7.456C7.525,8.032,7.526,8.97,8.103,9.549c0.578,0.577,1.516,0.577,2.095,0.001c0.576-0.578,0.576-1.517,0-2.095
+               C9.617,6.879,8.68,6.878,8.104,7.456z"/>
+</g>
+</svg>
diff --git a/resources/oojs-ui/images/icons/window.png b/resources/oojs-ui/images/icons/window.png
new file mode 100644 (file)
index 0000000..3d48a3c
Binary files /dev/null and b/resources/oojs-ui/images/icons/window.png differ
diff --git a/resources/oojs-ui/images/icons/window.svg b/resources/oojs-ui/images/icons/window.svg
new file mode 100644 (file)
index 0000000..621cf2c
--- /dev/null
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px"
+        height="24px" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
+<g id="window" style="opacity:0.75;">
+       <rect id="title" x="7" y="10" width="10" height="1"/>
+       <path id="window" d="M16,19H8c-2.206,0-4-1.794-4-4V9c0-2.206,1.794-4,4-4h8c2.206,0,4,1.794,4,4v6C20,17.206,18.206,19,16,19z
+                M8,7C6.897,7,6,7.897,6,9v6c0,1.103,0.897,2,2,2h8c1.103,0,2-0.897,2-2V9c0-1.103-0.897-2-2-2H8z"/>
+</g>
+</svg>
diff --git a/resources/oojs-ui/images/indicators/down.png b/resources/oojs-ui/images/indicators/down.png
new file mode 100644 (file)
index 0000000..47ff54c
Binary files /dev/null and b/resources/oojs-ui/images/indicators/down.png differ
diff --git a/resources/oojs-ui/images/indicators/down.svg b/resources/oojs-ui/images/indicators/down.svg
new file mode 100644 (file)
index 0000000..c871f60
--- /dev/null
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="12px"
+        height="12px" viewBox="0 0 12 12" style="enable-background:new 0 0 12 12;" xml:space="preserve">
+<g id="down" style="opacity:0.75;">
+       <polygon id="arrow" style="fill-rule:evenodd;clip-rule:evenodd;" points="2.023,3 5.512,8.953 9,3"/>
+</g>
+</svg>
diff --git a/resources/oojs-ui/images/indicators/required.png b/resources/oojs-ui/images/indicators/required.png
new file mode 100644 (file)
index 0000000..aeb35a3
Binary files /dev/null and b/resources/oojs-ui/images/indicators/required.png differ
diff --git a/resources/oojs-ui/images/indicators/required.svg b/resources/oojs-ui/images/indicators/required.svg
new file mode 100644 (file)
index 0000000..7c60ec0
--- /dev/null
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="12" height="12" viewBox="0, 0, 12, 12">
+  <g id="required" opacity="0.75">
+    <path d="M7,0 L7,4.268 L10.696,2.134 L11.696,3.866 L8,6 L11.696,8.134 L10.696,9.866 L7,7.732 L7,12 L5,12 L5,7.732 L1.304,9.866 L0.304,8.134 L4,6 L0.304,3.866 L1.304,2.134 L5,4.268 L5,0 z" fill="#000000"/>
+  </g>
+  <defs/>
+</svg>
diff --git a/resources/oojs-ui/images/indicators/up.png b/resources/oojs-ui/images/indicators/up.png
new file mode 100644 (file)
index 0000000..b827f6d
Binary files /dev/null and b/resources/oojs-ui/images/indicators/up.png differ
diff --git a/resources/oojs-ui/images/indicators/up.svg b/resources/oojs-ui/images/indicators/up.svg
new file mode 100644 (file)
index 0000000..a5d7f38
--- /dev/null
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="12px"
+        height="12px" viewBox="0 0 12 12" style="enable-background:new 0 0 12 12;" xml:space="preserve">
+<g id="up" style="opacity:0.75;">
+       <polygon id="arrow" style="fill-rule:evenodd;clip-rule:evenodd;" points="5.512,2.006 2,8 9.024,8                "/>
+</g>
+</svg>
diff --git a/resources/oojs-ui/images/tail.svg b/resources/oojs-ui/images/tail.svg
new file mode 100644 (file)
index 0000000..4df8bb2
--- /dev/null
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+        width="15px" height="8px" viewBox="0 0 15 8" style="enable-background:new 0 0 15 8;" xml:space="preserve">
+<g id="tail">
+       <polygon id="outline" style="fill-rule:evenodd;clip-rule:evenodd;fill:#808080;" points="7.609,2.499 2.096,8 13.125,8"/>
+       <polygon id="fill" style="fill-rule:evenodd;clip-rule:evenodd;fill:#FFFFFF;" points="7.609,3 2.598,8 12.622,8"/>
+</g>
+</svg>
diff --git a/resources/oojs-ui/images/textures/pending.gif b/resources/oojs-ui/images/textures/pending.gif
new file mode 100644 (file)
index 0000000..1194eed
Binary files /dev/null and b/resources/oojs-ui/images/textures/pending.gif differ
diff --git a/resources/oojs-ui/images/textures/transparency.png b/resources/oojs-ui/images/textures/transparency.png
new file mode 100644 (file)
index 0000000..b8e36d3
Binary files /dev/null and b/resources/oojs-ui/images/textures/transparency.png differ
diff --git a/resources/oojs-ui/images/toolbar-shadow.png b/resources/oojs-ui/images/toolbar-shadow.png
new file mode 100644 (file)
index 0000000..97e8d13
Binary files /dev/null and b/resources/oojs-ui/images/toolbar-shadow.png differ
diff --git a/resources/oojs-ui/oojs-ui.js b/resources/oojs-ui/oojs-ui.js
new file mode 100644 (file)
index 0000000..07bb2a8
--- /dev/null
@@ -0,0 +1,7467 @@
+/*!
+ * OOjs UI v0.1.0-pre (7788dc6700)
+ * https://www.mediawiki.org/wiki/OOjs_UI
+ *
+ * Copyright 2011–2014 OOjs Team and other contributors.
+ * Released under the MIT license
+ * http://oojs.mit-license.org
+ *
+ * Date: Thu Feb 13 2014 13:56:07 GMT-0800 (PST)
+ */
+( function () {
+
+'use strict';
+/**
+ * Namespace for all classes, static methods and static properties.
+ *
+ * @class
+ * @singleton
+ */
+OO.ui = {};
+
+OO.ui.bind = $.proxy;
+
+/**
+ * Get the user's language and any fallback languages.
+ *
+ * These language codes are used to localize user interface elements in the user's language.
+ *
+ * In environments that provide a localization system, this function should be overridden to
+ * return the user's language(s). The default implementation returns English (en) only.
+ *
+ * @returns {string[]} Language codes, in descending order of priority
+ */
+OO.ui.getUserLanguages = function () {
+       return [ 'en' ];
+};
+
+/**
+ * Get a value in an object keyed by language code.
+ *
+ * @param {Object.<string,Mixed>} obj Object keyed by language code
+ * @param {string|null} [lang] Language code, if omitted or null defaults to any user language
+ * @param {string} [fallback] Fallback code, used if no matching language can be found
+ * @returns {Mixed} Local value
+ */
+OO.ui.getLocalValue = function ( obj, lang, fallback ) {
+       var i, len, langs;
+
+       // Requested language
+       if ( obj[lang] ) {
+               return obj[lang];
+       }
+       // Known user language
+       langs = OO.ui.getUserLanguages();
+       for ( i = 0, len = langs.length; i < len; i++ ) {
+               lang = langs[i];
+               if ( obj[lang] ) {
+                       return obj[lang];
+               }
+       }
+       // Fallback language
+       if ( obj[fallback] ) {
+               return obj[fallback];
+       }
+       // First existing language
+       for ( lang in obj ) {
+               return obj[lang];
+       }
+
+       return undefined;
+};
+
+( function () {
+
+/**
+ * Message store for the default implementation of OO.ui.msg
+ *
+ * Environments that provide a localization system should not use this, but should override
+ * OO.ui.msg altogether.
+ *
+ * @private
+ */
+var messages = {
+       // Label text for button to exit from dialog
+       'ooui-dialog-action-close': 'Close',
+       // Tool tip for a button that moves items in a list down one place
+       'ooui-outline-control-move-down': 'Move item down',
+       // Tool tip for a button that moves items in a list up one place
+       'ooui-outline-control-move-up': 'Move item up',
+       // Label for the toolbar group that contains a list of all other available tools
+       'ooui-toolbar-more': 'More'
+};
+
+/**
+ * Get a localized message.
+ *
+ * In environments that provide a localization system, this function should be overridden to
+ * return the message translated in the user's language. The default implementation always returns
+ * English messages.
+ *
+ * After the message key, message parameters may optionally be passed. In the default implementation,
+ * any occurrences of $1 are replaced with the first parameter, $2 with the second parameter, etc.
+ * Alternative implementations of OO.ui.msg may use any substitution system they like, as long as
+ * they support unnamed, ordered message parameters.
+ *
+ * @abstract
+ * @param {string} key Message key
+ * @param {Mixed...} [params] Message parameters
+ * @returns {string} Translated message with parameters substituted
+ */
+OO.ui.msg = function ( key ) {
+       var message = messages[key], params = Array.prototype.slice.call( arguments, 1 );
+       if ( typeof message === 'string' ) {
+               // Perform $1 substitution
+               message = message.replace( /\$(\d+)/g, function ( unused, n ) {
+                       var i = parseInt( n, 10 );
+                       return params[i - 1] !== undefined ? params[i - 1] : '$' + n;
+               } );
+       } else {
+               // Return placeholder if message not found
+               message = '[' + key + ']';
+       }
+       return message;
+};
+
+OO.ui.deferMsg = function ( key ) {
+       return function () {
+               return OO.ui.msg( key );
+       };
+};
+
+OO.ui.resolveMsg = function ( msg ) {
+       if ( $.isFunction( msg ) ) {
+               return msg();
+       }
+       return msg;
+};
+
+} )();
+
+// Add more as you need
+OO.ui.Keys = {
+       'UNDEFINED': 0,
+       'BACKSPACE': 8,
+       'DELETE': 46,
+       'LEFT': 37,
+       'RIGHT': 39,
+       'UP': 38,
+       'DOWN': 40,
+       'ENTER': 13,
+       'END': 35,
+       'HOME': 36,
+       'TAB': 9,
+       'PAGEUP': 33,
+       'PAGEDOWN': 34,
+       'ESCAPE': 27,
+       'SHIFT': 16,
+       'SPACE': 32
+};
+/**
+ * DOM element abstraction.
+ *
+ * @class
+ * @abstract
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ * @cfg {Function} [$] jQuery for the frame the widget is in
+ * @cfg {string[]} [classes] CSS class names
+ * @cfg {jQuery} [$content] Content elements to append
+ */
+OO.ui.Element = function OoUiElement( config ) {
+       // Configuration initialization
+       config = config || {};
+
+       // Properties
+       this.$ = config.$ || OO.ui.Element.getJQuery( document );
+       this.$element = this.$( this.$.context.createElement( this.getTagName() ) );
+       this.elementGroup = null;
+
+       // Initialization
+       if ( Array.isArray( config.classes ) ) {
+               this.$element.addClass( config.classes.join( ' ' ) );
+       }
+       if ( config.$content ) {
+               this.$element.append( config.$content );
+       }
+};
+
+/* Static Properties */
+
+/**
+ * @static
+ * @property
+ * @inheritable
+ */
+OO.ui.Element.static = {};
+
+/**
+ * HTML tag name.
+ *
+ * This may be ignored if getTagName is overridden.
+ *
+ * @static
+ * @property {string}
+ * @inheritable
+ */
+OO.ui.Element.static.tagName = 'div';
+
+/* Static Methods */
+
+/**
+ * Gets a jQuery function within a specific document.
+ *
+ * @static
+ * @param {jQuery|HTMLElement|HTMLDocument|Window} context Context to bind the function to
+ * @param {OO.ui.Frame} [frame] Frame of the document context
+ * @returns {Function} Bound jQuery function
+ */
+OO.ui.Element.getJQuery = function ( context, frame ) {
+       function wrapper( selector ) {
+               return $( selector, wrapper.context );
+       }
+
+       wrapper.context = this.getDocument( context );
+
+       if ( frame ) {
+               wrapper.frame = frame;
+       }
+
+       return wrapper;
+};
+
+/**
+ * Get the document of an element.
+ *
+ * @static
+ * @param {jQuery|HTMLElement|HTMLDocument|Window} obj Object to get the document for
+ * @returns {HTMLDocument} Document object
+ * @throws {Error} If context is invalid
+ */
+OO.ui.Element.getDocument = function ( obj ) {
+       var doc =
+               // jQuery - selections created "offscreen" won't have a context, so .context isn't reliable
+               ( obj[0] && obj[0].ownerDocument ) ||
+               // Empty jQuery selections might have a context
+               obj.context ||
+               // HTMLElement
+               obj.ownerDocument ||
+               // Window
+               obj.document ||
+               // HTMLDocument
+               ( obj.nodeType === 9 && obj );
+
+       if ( doc ) {
+               return doc;
+       }
+
+       throw new Error( 'Invalid context' );
+};
+
+/**
+ * Get the window of an element or document.
+ *
+ * @static
+ * @param {jQuery|HTMLElement|HTMLDocument|Window} obj Context to get the window for
+ * @returns {Window} Window object
+ */
+OO.ui.Element.getWindow = function ( obj ) {
+       var doc = this.getDocument( obj );
+       return doc.parentWindow || doc.defaultView;
+};
+
+/**
+ * Get the direction of an element or document.
+ *
+ * @static
+ * @param {jQuery|HTMLElement|HTMLDocument|Window} obj Context to get the direction for
+ * @returns {string} Text direction, either `ltr` or `rtl`
+ */
+OO.ui.Element.getDir = function ( obj ) {
+       var isDoc, isWin;
+
+       if ( obj instanceof jQuery ) {
+               obj = obj[0];
+       }
+       isDoc = obj.nodeType === 9;
+       isWin = obj.document !== undefined;
+       if ( isDoc || isWin ) {
+               if ( isWin ) {
+                       obj = obj.document;
+               }
+               obj = obj.body;
+       }
+       return $( obj ).css( 'direction' );
+};
+
+/**
+ * Get the offset between two frames.
+ *
+ * TODO: Make this function not use recursion.
+ *
+ * @static
+ * @param {Window} from Window of the child frame
+ * @param {Window} [to=window] Window of the parent frame
+ * @param {Object} [offset] Offset to start with, used internally
+ * @returns {Object} Offset object, containing left and top properties
+ */
+OO.ui.Element.getFrameOffset = function ( from, to, offset ) {
+       var i, len, frames, frame, rect;
+
+       if ( !to ) {
+               to = window;
+       }
+       if ( !offset ) {
+               offset = { 'top': 0, 'left': 0 };
+       }
+       if ( from.parent === from ) {
+               return offset;
+       }
+
+       // Get iframe element
+       frames = from.parent.document.getElementsByTagName( 'iframe' );
+       for ( i = 0, len = frames.length; i < len; i++ ) {
+               if ( frames[i].contentWindow === from ) {
+                       frame = frames[i];
+                       break;
+               }
+       }
+
+       // Recursively accumulate offset values
+       if ( frame ) {
+               rect = frame.getBoundingClientRect();
+               offset.left += rect.left;
+               offset.top += rect.top;
+               if ( from !== to ) {
+                       this.getFrameOffset( from.parent, offset );
+               }
+       }
+       return offset;
+};
+
+/**
+ * Get the offset between two elements.
+ *
+ * @static
+ * @param {jQuery} $from
+ * @param {jQuery} $to
+ * @returns {Object} Translated position coordinates, containing top and left properties
+ */
+OO.ui.Element.getRelativePosition = function ( $from, $to ) {
+       var from = $from.offset(),
+               to = $to.offset();
+       return { 'top': Math.round( from.top - to.top ), 'left': Math.round( from.left - to.left ) };
+};
+
+/**
+ * Get element border sizes.
+ *
+ * @static
+ * @param {HTMLElement} el Element to measure
+ * @return {Object} Dimensions object with `top`, `left`, `bottom` and `right` properties
+ */
+OO.ui.Element.getBorders = function ( el ) {
+       var doc = el.ownerDocument,
+               win = doc.parentWindow || doc.defaultView,
+               style = win && win.getComputedStyle ?
+                       win.getComputedStyle( el, null ) :
+                       el.currentStyle,
+               $el = $( el ),
+               top = parseFloat( style ? style.borderTopWidth : $el.css( 'borderTopWidth' ) ) || 0,
+               left = parseFloat( style ? style.borderLeftWidth : $el.css( 'borderLeftWidth' ) ) || 0,
+               bottom = parseFloat( style ? style.borderBottomWidth : $el.css( 'borderBottomWidth' ) ) || 0,
+               right = parseFloat( style ? style.borderRightWidth : $el.css( 'borderRightWidth' ) ) || 0;
+
+       return {
+               'top': Math.round( top ),
+               'left': Math.round( left ),
+               'bottom': Math.round( bottom ),
+               'right': Math.round( right )
+       };
+};
+
+/**
+ * Get dimensions of an element or window.
+ *
+ * @static
+ * @param {HTMLElement|Window} el Element to measure
+ * @return {Object} Dimensions object with `borders`, `scroll`, `scrollbar` and `rect` properties
+ */
+OO.ui.Element.getDimensions = function ( el ) {
+       var $el, $win,
+               doc = el.ownerDocument || el.document,
+               win = doc.parentWindow || doc.defaultView;
+
+       if ( win === el || el === doc.documentElement ) {
+               $win = $( win );
+               return {
+                       'borders': { 'top': 0, 'left': 0, 'bottom': 0, 'right': 0 },
+                       'scroll': {
+                               'top': $win.scrollTop(),
+                               'left': $win.scrollLeft()
+                       },
+                       'scrollbar': { 'right': 0, 'bottom': 0 },
+                       'rect': {
+                               'top': 0,
+                               'left': 0,
+                               'bottom': $win.innerHeight(),
+                               'right': $win.innerWidth()
+                       }
+               };
+       } else {
+               $el = $( el );
+               return {
+                       'borders': this.getBorders( el ),
+                       'scroll': {
+                               'top': $el.scrollTop(),
+                               'left': $el.scrollLeft()
+                       },
+                       'scrollbar': {
+                               'right': $el.innerWidth() - el.clientWidth,
+                               'bottom': $el.innerHeight() - el.clientHeight
+                       },
+                       'rect': el.getBoundingClientRect()
+               };
+       }
+};
+
+/**
+ * Get closest scrollable container.
+ *
+ * Traverses up until either a scrollable element or the root is reached, in which case the window
+ * will be returned.
+ *
+ * @static
+ * @param {HTMLElement} el Element to find scrollable container for
+ * @param {string} [dimension] Dimension of scrolling to look for; `x`, `y` or omit for either
+ * @return {HTMLElement|Window} Closest scrollable container
+ */
+OO.ui.Element.getClosestScrollableContainer = function ( el, dimension ) {
+       var i, val,
+               props = [ 'overflow' ],
+               $parent = $( el ).parent();
+
+       if ( dimension === 'x' || dimension === 'y' ) {
+               props.push( 'overflow-' + dimension );
+       }
+
+       while ( $parent.length ) {
+               if ( $parent[0] === el.ownerDocument.body ) {
+                       return $parent[0];
+               }
+               i = props.length;
+               while ( i-- ) {
+                       val = $parent.css( props[i] );
+                       if ( val === 'auto' || val === 'scroll' ) {
+                               return $parent[0];
+                       }
+               }
+               $parent = $parent.parent();
+       }
+       return this.getDocument( el ).body;
+};
+
+/**
+ * Scroll element into view
+ *
+ * @static
+ * @param {HTMLElement} el Element to scroll into view
+ * @param {Object} [config={}] Configuration config
+ * @param {string} [config.duration] jQuery animation duration value
+ * @param {string} [config.direction] Scroll in only one direction, e.g. 'x' or 'y', omit
+ *  to scroll in both directions
+ * @param {Function} [config.complete] Function to call when scrolling completes
+ */
+OO.ui.Element.scrollIntoView = function ( el, config ) {
+       // Configuration initialization
+       config = config || {};
+
+       var anim = {},
+               callback = typeof config.complete === 'function' && config.complete,
+               sc = this.getClosestScrollableContainer( el, config.direction ),
+               $sc = $( sc ),
+               eld = this.getDimensions( el ),
+               scd = this.getDimensions( sc ),
+               rel = {
+                       'top': eld.rect.top - ( scd.rect.top + scd.borders.top ),
+                       'bottom': scd.rect.bottom - scd.borders.bottom - scd.scrollbar.bottom - eld.rect.bottom,
+                       'left': eld.rect.left - ( scd.rect.left + scd.borders.left ),
+                       'right': scd.rect.right - scd.borders.right - scd.scrollbar.right - eld.rect.right
+               };
+
+       if ( !config.direction || config.direction === 'y' ) {
+               if ( rel.top < 0 ) {
+                       anim.scrollTop = scd.scroll.top + rel.top;
+               } else if ( rel.top > 0 && rel.bottom < 0 ) {
+                       anim.scrollTop = scd.scroll.top + Math.min( rel.top, -rel.bottom );
+               }
+       }
+       if ( !config.direction || config.direction === 'x' ) {
+               if ( rel.left < 0 ) {
+                       anim.scrollLeft = scd.scroll.left + rel.left;
+               } else if ( rel.left > 0 && rel.right < 0 ) {
+                       anim.scrollLeft = scd.scroll.left + Math.min( rel.left, -rel.right );
+               }
+       }
+       if ( !$.isEmptyObject( anim ) ) {
+               $sc.stop( true ).animate( anim, config.duration || 'fast' );
+               if ( callback ) {
+                       $sc.queue( function ( next ) {
+                               callback();
+                               next();
+                       } );
+               }
+       } else {
+               if ( callback ) {
+                       callback();
+               }
+       }
+};
+
+/* Methods */
+
+/**
+ * Get the HTML tag name.
+ *
+ * Override this method to base the result on instance information.
+ *
+ * @returns {string} HTML tag name
+ */
+OO.ui.Element.prototype.getTagName = function () {
+       return this.constructor.static.tagName;
+};
+
+/**
+ * Get the DOM document.
+ *
+ * @returns {HTMLDocument} Document object
+ */
+OO.ui.Element.prototype.getElementDocument = function () {
+       return OO.ui.Element.getDocument( this.$element );
+};
+
+/**
+ * Get the DOM window.
+ *
+ * @returns {Window} Window object
+ */
+OO.ui.Element.prototype.getElementWindow = function () {
+       return OO.ui.Element.getWindow( this.$element );
+};
+
+/**
+ * Get closest scrollable container.
+ *
+ * @method
+ * @see #static-method-getClosestScrollableContainer
+ */
+OO.ui.Element.prototype.getClosestScrollableElementContainer = function () {
+       return OO.ui.Element.getClosestScrollableContainer( this.$element[0] );
+};
+
+/**
+ * Get group element is in.
+ *
+ * @returns {OO.ui.GroupElement|null} Group element, null if none
+ */
+OO.ui.Element.prototype.getElementGroup = function () {
+       return this.elementGroup;
+};
+
+/**
+ * Set group element is in.
+ *
+ * @param {OO.ui.GroupElement|null} group Group element, null if none
+ * @chainable
+ */
+OO.ui.Element.prototype.setElementGroup = function ( group ) {
+       this.elementGroup = group;
+       return this;
+};
+
+/**
+ * Scroll element into view
+ *
+ * @method
+ * @see #static-method-scrollIntoView
+ * @param {Object} [config={}]
+ */
+OO.ui.Element.prototype.scrollElementIntoView = function ( config ) {
+       return OO.ui.Element.scrollIntoView( this.$element[0], config );
+};
+
+( function () {
+       // Static
+       var specialFocusin;
+
+       function handler( e ) {
+               jQuery.event.simulate( 'focusin', e.target, jQuery.event.fix( e ), /* bubble = */ true );
+       }
+
+       specialFocusin = {
+               setup: function () {
+                       var doc = this.ownerDocument || this,
+                               attaches = $.data( doc, 'ooui-focusin-attaches' );
+                       if ( !attaches ) {
+                               doc.addEventListener( 'focus', handler, true );
+                       }
+                       $.data( doc, 'ooui-focusin-attaches', ( attaches || 0 ) + 1 );
+               },
+               teardown: function () {
+                       var doc = this.ownerDocument || this,
+                               attaches = $.data( doc, 'ooui-focusin-attaches' ) - 1;
+                       if ( !attaches ) {
+                               doc.removeEventListener( 'focus', handler, true );
+                               $.removeData( doc, 'ooui-focusin-attaches' );
+                       } else {
+                               $.data( doc, 'ooui-focusin-attaches', attaches );
+                       }
+               }
+       };
+
+       /**
+        * Bind a handler for an event on the DOM element.
+        *
+        * Uses jQuery internally for everything except for events which are
+        * known to have issues in the browser or in jQuery. This method
+        * should become obsolete eventually.
+        *
+        * @param {string} event
+        * @param {Function} callback
+        */
+       OO.ui.Element.prototype.onDOMEvent = function ( event, callback ) {
+               var orig;
+
+               if ( event === 'focusin' ) {
+                       // jQuery 1.8.3 has a bug with handling focusin events inside iframes.
+                       // Firefox doesn't support focusin at all, so we listen for 'focus' on the
+                       // document, and simulate a 'focusin' event on the target element and make
+                       // it bubble from there.
+                       //
+                       // - http://jsfiddle.net/sw3hr/
+                       // - http://bugs.jquery.com/ticket/14180
+                       // - https://github.com/jquery/jquery/commit/1cecf64e5aa4153
+
+                       // Replace jQuery's override with our own
+                       orig = $.event.special.focusin;
+                       $.event.special.focusin = specialFocusin;
+
+                       this.$element.on( event, callback );
+
+                       // Restore
+                       $.event.special.focusin = orig;
+
+               } else {
+                       this.$element.on( event, callback );
+               }
+       };
+
+       /**
+        * @param {string} event
+        * @param {Function} callback
+        */
+       OO.ui.Element.prototype.offDOMEvent = function ( event, callback ) {
+               var orig;
+               if ( event === 'focusin' ) {
+                       orig = $.event.special.focusin;
+                       $.event.special.focusin = specialFocusin;
+                       this.$element.off( event, callback );
+                       $.event.special.focusin = orig;
+               } else {
+                       this.$element.off( event, callback );
+               }
+       };
+}() );
+/**
+ * Embedded iframe with the same styles as its parent.
+ *
+ * @class
+ * @extends OO.ui.Element
+ * @mixins OO.EventEmitter
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ */
+OO.ui.Frame = function OoUiFrame( config ) {
+       // Parent constructor
+       OO.ui.Element.call( this, config );
+
+       // Mixin constructors
+       OO.EventEmitter.call( this );
+
+       // Properties
+       this.initialized = false;
+       this.config = config;
+
+       // Initialize
+       this.$element
+               .addClass( 'oo-ui-frame' )
+               .attr( { 'frameborder': 0, 'scrolling': 'no' } );
+
+};
+
+/* Inheritance */
+
+OO.inheritClass( OO.ui.Frame, OO.ui.Element );
+
+OO.mixinClass( OO.ui.Frame, OO.EventEmitter );
+
+/* Static Properties */
+
+OO.ui.Frame.static.tagName = 'iframe';
+
+/* Events */
+
+/**
+ * @event initialize
+ */
+
+/* Static Methods */
+
+/**
+ * Transplant the CSS styles from as parent document to a frame's document.
+ *
+ * This loops over the style sheets in the parent document, and copies their nodes to the
+ * frame's document. It then polls the document to see when all styles have loaded, and once they
+ * have, invokes the callback.
+ *
+ * If the styles still haven't loaded after a long time (5 seconds by default), we give up waiting
+ * and invoke the callback anyway. This protects against cases like a display: none; iframe in
+ * Firefox, where the styles won't load until the iframe becomes visible.
+ *
+ * For details of how we arrived at the strategy used in this function, see #load.
+ *
+ * @static
+ * @method
+ * @inheritable
+ * @param {HTMLDocument} parentDoc Document to transplant styles from
+ * @param {HTMLDocument} frameDoc Document to transplant styles to
+ * @param {Function} [callback] Callback to execute once styles have loaded
+ * @param {number} [timeout=5000] How long to wait before giving up (in ms). If 0, never give up.
+ */
+OO.ui.Frame.static.transplantStyles = function ( parentDoc, frameDoc, callback, timeout ) {
+       var i, numSheets, styleNode, newNode, timeoutID, pollNodeId, $pendingPollNodes,
+               $pollNodes = $( [] ),
+               // Fake font-family value
+               fontFamily = 'oo-ui-frame-transplantStyles-loaded';
+
+       for ( i = 0, numSheets = parentDoc.styleSheets.length; i < numSheets; i++ ) {
+               styleNode = parentDoc.styleSheets[i].ownerNode;
+               if ( callback && styleNode.nodeName.toLowerCase() === 'link' ) {
+                       // External stylesheet
+                       // Create a node with a unique ID that we're going to monitor to see when the CSS
+                       // has loaded
+                       pollNodeId = 'oo-ui-frame-transplantStyles-loaded-' + i;
+                       $pollNodes = $pollNodes.add( $( '<div>', frameDoc )
+                               .attr( 'id', pollNodeId )
+                               .appendTo( frameDoc.body )
+                       );
+
+                       // Add <style>@import url(...); #pollNodeId { font-family: ... }</style>
+                       // The font-family rule will only take effect once the @import finishes
+                       newNode = frameDoc.createElement( 'style' );
+                       newNode.textContent = '@import url(' + styleNode.href + ');\n' +
+                               '#' + pollNodeId + ' { font-family: ' + fontFamily + '; }';
+               } else {
+                       // Not an external stylesheet, or no polling required; just copy the node over
+                       newNode = frameDoc.importNode( styleNode, true );
+               }
+               frameDoc.head.appendChild( newNode );
+       }
+
+       if ( callback ) {
+               // Poll every 100ms until all external stylesheets have loaded
+               $pendingPollNodes = $pollNodes;
+               timeoutID = setTimeout( function pollExternalStylesheets() {
+                       while (
+                               $pendingPollNodes.length > 0 &&
+                               $pendingPollNodes.eq( 0 ).css( 'font-family' ) === fontFamily
+                       ) {
+                               $pendingPollNodes = $pendingPollNodes.slice( 1 );
+                       }
+
+                       if ( $pendingPollNodes.length === 0 ) {
+                               // We're done!
+                               if ( timeoutID !== null ) {
+                                       timeoutID = null;
+                                       $pollNodes.remove();
+                                       callback();
+                               }
+                       } else {
+                               timeoutID = setTimeout( pollExternalStylesheets, 100 );
+                       }
+               }, 100 );
+               // ...but give up after a while
+               if ( timeout !== 0 ) {
+                       setTimeout( function () {
+                               if ( timeoutID ) {
+                                       clearTimeout( timeoutID );
+                                       timeoutID = null;
+                                       $pollNodes.remove();
+                                       callback();
+                               }
+                       }, timeout || 5000 );
+               }
+       }
+};
+
+/* Methods */
+
+/**
+ * Load the frame contents.
+ *
+ * Once the iframe's stylesheets are loaded, the `initialize` event will be emitted.
+ *
+ * Sounds simple right? Read on...
+ *
+ * When you create a dynamic iframe using open/write/close, the window.load event for the
+ * iframe is triggered when you call close, and there's no further load event to indicate that
+ * everything is actually loaded.
+ *
+ * In Chrome, stylesheets don't show up in document.styleSheets until they have loaded, so we could
+ * just poll that array and wait for it to have the right length. However, in Firefox, stylesheets
+ * are added to document.styleSheets immediately, and the only way you can determine whether they've
+ * loaded is to attempt to access .cssRules and wait for that to stop throwing an exception. But
+ * cross-domain stylesheets never allow .cssRules to be accessed even after they have loaded.
+ *
+ * The workaround is to change all `<link href="...">` tags to `<style>@import url(...)</style>` tags.
+ * Because `@import` is blocking, Chrome won't add the stylesheet to document.styleSheets until
+ * the `@import` has finished, and Firefox won't allow .cssRules to be accessed until the `@import`
+ * has finished. And because the contents of the `<style>` tag are from the same origin, accessing
+ * .cssRules is allowed.
+ *
+ * However, now that we control the styles we're injecting, we might as well do away with
+ * browser-specific polling hacks like document.styleSheets and .cssRules, and instead inject
+ * `<style>@import url(...); #foo { font-family: someValue; }</style>`, then create `<div id="foo">`
+ * and wait for its font-family to change to someValue. Because `@import` is blocking, the font-family
+ * rule is not applied until after the `@import` finishes.
+ *
+ * All this stylesheet injection and polling magic is in #transplantStyles.
+ *
+ * @fires initialize
+ */
+OO.ui.Frame.prototype.load = function () {
+       var win = this.$element.prop( 'contentWindow' ),
+               doc = win.document,
+               frame = this;
+
+       // Figure out directionality:
+       this.dir = this.$element.closest( '[dir]' ).prop( 'dir' ) || 'ltr';
+
+       // Initialize contents
+       doc.open();
+       doc.write(
+               '<!doctype html>' +
+               '<html>' +
+                       '<body class="oo-ui-frame-body oo-ui-' + this.dir + '" style="direction:' + this.dir + ';" dir="' + this.dir + '">' +
+                               '<div class="oo-ui-frame-content"></div>' +
+                       '</body>' +
+               '</html>'
+       );
+       doc.close();
+
+       // Properties
+       this.$ = OO.ui.Element.getJQuery( doc, this );
+       this.$content = this.$( '.oo-ui-frame-content' );
+       this.$document = this.$( doc );
+
+       this.constructor.static.transplantStyles( this.getElementDocument(), this.$document[0],
+               function () {
+                       frame.initialized = true;
+                       frame.emit( 'initialize' );
+               }
+       );
+};
+
+/**
+ * Run a callback as soon as the frame has been initialized.
+ *
+ * @param {Function} callback
+ */
+OO.ui.Frame.prototype.run = function ( callback ) {
+       if ( this.initialized ) {
+               callback();
+       } else {
+               this.once( 'initialize', callback );
+       }
+};
+
+/**
+ * Sets the size of the frame.
+ *
+ * @method
+ * @param {number} width Frame width in pixels
+ * @param {number} height Frame height in pixels
+ * @chainable
+ */
+OO.ui.Frame.prototype.setSize = function ( width, height ) {
+       this.$element.css( { 'width': width, 'height': height } );
+       return this;
+};
+/**
+ * Container for elements in a child frame.
+ *
+ * There are two ways to specify a title: set the static `title` property or provide a `title`
+ * property in the configuration options. The latter will override the former.
+ *
+ * @class
+ * @abstract
+ * @extends OO.ui.Element
+ * @mixins OO.EventEmitter
+ *
+ * @constructor
+ * @param {OO.ui.WindowSet} windowSet Window set this dialog is part of
+ * @param {Object} [config] Configuration options
+ * @cfg {string|Function} [title] Title string or function that returns a string
+ * @cfg {string} [icon] Symbolic name of icon
+ * @fires initialize
+ */
+OO.ui.Window = function OoUiWindow( windowSet, config ) {
+       // Parent constructor
+       OO.ui.Element.call( this, config );
+
+       // Mixin constructors
+       OO.EventEmitter.call( this );
+
+       // Properties
+       this.windowSet = windowSet;
+       this.visible = false;
+       this.opening = false;
+       this.closing = false;
+       this.title = OO.ui.resolveMsg( config.title || this.constructor.static.title );
+       this.icon = config.icon || this.constructor.static.icon;
+       this.frame = new OO.ui.Frame( { '$': this.$ } );
+       this.$frame = this.$( '<div>' );
+       this.$ = function () {
+               throw new Error( 'this.$() cannot be used until the frame has been initialized.' );
+       };
+
+       // Initialization
+       this.$element
+               .addClass( 'oo-ui-window' )
+               // Hide the window using visibility: hidden; while the iframe is still loading
+               // Can't use display: none; because that prevents the iframe from loading in Firefox
+               .css( 'visibility', 'hidden' )
+               .append( this.$frame );
+       this.$frame
+               .addClass( 'oo-ui-window-frame' )
+               .append( this.frame.$element );
+
+       // Events
+       this.frame.connect( this, { 'initialize': 'initialize' } );
+};
+
+/* Inheritance */
+
+OO.inheritClass( OO.ui.Window, OO.ui.Element );
+
+OO.mixinClass( OO.ui.Window, OO.EventEmitter );
+
+/* Events */
+
+/**
+ * Initialize contents.
+ *
+ * Fired asynchronously after construction when iframe is ready.
+ *
+ * @event initialize
+ */
+
+/**
+ * Open window.
+ *
+ * Fired after window has been opened.
+ *
+ * @event open
+ * @param {Object} data Window opening data
+ */
+
+/**
+ * Close window.
+ *
+ * Fired after window has been closed.
+ *
+ * @event close
+ * @param {Object} data Window closing data
+ */
+
+/* Static Properties */
+
+/**
+ * Symbolic name of icon.
+ *
+ * @static
+ * @inheritable
+ * @property {string}
+ */
+OO.ui.Window.static.icon = 'window';
+
+/**
+ * Window title.
+ *
+ * @static
+ * @inheritable
+ * @property {string|Function} Title string or function that returns a string
+ */
+OO.ui.Window.static.title = null;
+
+/* Methods */
+
+/**
+ * Check if window is visible.
+ *
+ * @method
+ * @returns {boolean} Window is visible
+ */
+OO.ui.Window.prototype.isVisible = function () {
+       return this.visible;
+};
+
+/**
+ * Check if window is opening.
+ *
+ * @method
+ * @returns {boolean} Window is opening
+ */
+OO.ui.Window.prototype.isOpening = function () {
+       return this.opening;
+};
+
+/**
+ * Check if window is closing.
+ *
+ * @method
+ * @returns {boolean} Window is closing
+ */
+OO.ui.Window.prototype.isClosing = function () {
+       return this.closing;
+};
+
+/**
+ * Get the window frame.
+ *
+ * @method
+ * @returns {OO.ui.Frame} Frame of window
+ */
+OO.ui.Window.prototype.getFrame = function () {
+       return this.frame;
+};
+
+/**
+ * Get the window set.
+ *
+ * @method
+ * @returns {OO.ui.WindowSet} Window set
+ */
+OO.ui.Window.prototype.getWindowSet = function () {
+       return this.windowSet;
+};
+
+/**
+ * Get the window title.
+ *
+ * @returns {string} Title text
+ */
+OO.ui.Window.prototype.getTitle = function () {
+       return this.title;
+};
+
+/**
+ * Get the window icon.
+ *
+ * @returns {string} Symbolic name of icon
+ */
+OO.ui.Window.prototype.getIcon = function () {
+       return this.icon;
+};
+
+/**
+ * Set the size of window frame.
+ *
+ * @param {number} [width=auto] Custom width
+ * @param {number} [height=auto] Custom height
+ * @chainable
+ */
+OO.ui.Window.prototype.setSize = function ( width, height ) {
+       if ( !this.frame.$content ) {
+               return;
+       }
+
+       this.frame.$element.css( {
+               'width': width === undefined ? 'auto' : width,
+               'height': height === undefined ? 'auto' : height
+       } );
+
+       return this;
+};
+
+/**
+ * Set the title of the window.
+ *
+ * @param {string|Function} title Title text or a function that returns text
+ * @chainable
+ */
+OO.ui.Window.prototype.setTitle = function ( title ) {
+       this.title = OO.ui.resolveMsg( title );
+       if ( this.$title ) {
+               this.$title.text( title );
+       }
+       return this;
+};
+
+/**
+ * Set the icon of the window.
+ *
+ * @param {string} icon Symbolic name of icon
+ * @chainable
+ */
+OO.ui.Window.prototype.setIcon = function ( icon ) {
+       if ( this.$icon ) {
+               this.$icon.removeClass( 'oo-ui-icon-' + this.icon );
+       }
+       this.icon = icon;
+       if ( this.$icon ) {
+               this.$icon.addClass( 'oo-ui-icon-' + this.icon );
+       }
+
+       return this;
+};
+
+/**
+ * Set the position of window to fit with contents..
+ *
+ * @param {string} left Left offset
+ * @param {string} top Top offset
+ * @chainable
+ */
+OO.ui.Window.prototype.setPosition = function ( left, top ) {
+       this.$element.css( { 'left': left, 'top': top } );
+       return this;
+};
+
+/**
+ * Set the height of window to fit with contents.
+ *
+ * @param {number} [min=0] Min height
+ * @param {number} [max] Max height (defaults to content's outer height)
+ * @chainable
+ */
+OO.ui.Window.prototype.fitHeightToContents = function ( min, max ) {
+       var height = this.frame.$content.outerHeight();
+
+       this.frame.$element.css(
+               'height', Math.max( min || 0, max === undefined ? height : Math.min( max, height ) )
+       );
+
+       return this;
+};
+
+/**
+ * Set the width of window to fit with contents.
+ *
+ * @param {number} [min=0] Min height
+ * @param {number} [max] Max height (defaults to content's outer width)
+ * @chainable
+ */
+OO.ui.Window.prototype.fitWidthToContents = function ( min, max ) {
+       var width = this.frame.$content.outerWidth();
+
+       this.frame.$element.css(
+               'width', Math.max( min || 0, max === undefined ? width : Math.min( max, width ) )
+       );
+
+       return this;
+};
+
+/**
+ * Initialize window contents.
+ *
+ * The first time the window is opened, #initialize is called when it's safe to begin populating
+ * its contents. See #setup for a way to make changes each time the window opens.
+ *
+ * Once this method is called, this.$$ can be used to create elements within the frame.
+ *
+ * @method
+ * @fires initialize
+ * @chainable
+ */
+OO.ui.Window.prototype.initialize = function () {
+       // Properties
+       this.$ = this.frame.$;
+       this.$title = this.$( '<div class="oo-ui-window-title"></div>' )
+               .text( this.title );
+       this.$icon = this.$( '<div class="oo-ui-window-icon"></div>' )
+               .addClass( 'oo-ui-icon-' + this.icon );
+       this.$head = this.$( '<div class="oo-ui-window-head"></div>' );
+       this.$body = this.$( '<div class="oo-ui-window-body"></div>' );
+       this.$foot = this.$( '<div class="oo-ui-window-foot"></div>' );
+       this.$overlay = this.$( '<div class="oo-ui-window-overlay"></div>' );
+
+       // Initialization
+       this.frame.$content.append(
+               this.$head.append( this.$icon, this.$title ),
+               this.$body,
+               this.$foot,
+               this.$overlay
+       );
+
+       // Undo the visibility: hidden; hack from the constructor and apply display: none;
+       // We can do this safely now that the iframe has initialized
+       this.$element.hide().css( 'visibility', '' );
+
+       this.emit( 'initialize' );
+
+       return this;
+};
+
+/**
+ * Setup window for use.
+ *
+ * Each time the window is opened, once it's ready to be interacted with, this will set it up for
+ * use in a particular context, based on the `data` argument.
+ *
+ * When you override this method, you must call the parent method at the very beginning.
+ *
+ * @method
+ * @abstract
+ * @param {Object} [data] Window opening data
+ */
+OO.ui.Window.prototype.setup = function () {
+       // Override to do something
+};
+
+/**
+ * Tear down window after use.
+ *
+ * Each time the window is closed, and it's done being interacted with, this will tear it down and
+ * do something with the user's interactions within the window, based on the `data` argument.
+ *
+ * When you override this method, you must call the parent method at the very end.
+ *
+ * @method
+ * @abstract
+ * @param {Object} [data] Window closing data
+ */
+OO.ui.Window.prototype.teardown = function () {
+       // Override to do something
+};
+
+/**
+ * Open window.
+ *
+ * Do not override this method. See #setup for a way to make changes each time the window opens.
+ *
+ * @method
+ * @param {Object} [data] Window opening data
+ * @fires open
+ * @chainable
+ */
+OO.ui.Window.prototype.open = function ( data ) {
+       if ( !this.opening && !this.closing && !this.visible ) {
+               this.opening = true;
+               this.frame.run( OO.ui.bind( function () {
+                       this.$element.show();
+                       this.visible = true;
+                       this.frame.$element.focus();
+                       this.emit( 'opening', data );
+                       this.setup( data );
+                       this.emit( 'open', data );
+                       this.opening = false;
+               }, this ) );
+       }
+
+       return this;
+};
+
+/**
+ * Close window.
+ *
+ * See #teardown for a way to do something each time the window closes.
+ *
+ * @method
+ * @param {Object} [data] Window closing data
+ * @fires close
+ * @chainable
+ */
+OO.ui.Window.prototype.close = function ( data ) {
+       if ( !this.opening && !this.closing && this.visible ) {
+               this.frame.$content.find( ':focus' ).blur();
+               this.closing = true;
+               this.$element.hide();
+               this.visible = false;
+               this.emit( 'closing', data );
+               this.teardown( data );
+               this.emit( 'close', data );
+               this.closing = false;
+       }
+
+       return this;
+};
+/**
+ * Set of mutually exclusive windows.
+ *
+ * @class
+ * @extends OO.ui.Element
+ * @mixins OO.EventEmitter
+ *
+ * @constructor
+ * @param {OO.Factory} factory Window factory
+ * @param {Object} [config] Configuration options
+ */
+OO.ui.WindowSet = function OoUiWindowSet( factory, config ) {
+       // Parent constructor
+       OO.ui.Element.call( this, config );
+
+       // Mixin constructors
+       OO.EventEmitter.call( this );
+
+       // Properties
+       this.factory = factory;
+       this.windows = {};
+       this.currentWindow = null;
+
+       // Initialization
+       this.$element.addClass( 'oo-ui-windowSet' );
+};
+
+/* Inheritance */
+
+OO.inheritClass( OO.ui.WindowSet, OO.ui.Element );
+
+OO.mixinClass( OO.ui.WindowSet, OO.EventEmitter );
+
+/* Events */
+
+/**
+ * @event opening
+ * @param {OO.ui.Window} win Window that's being opened
+ * @param {Object} config Window opening information
+ */
+
+/**
+ * @event open
+ * @param {OO.ui.Window} win Window that's been opened
+ * @param {Object} config Window opening information
+ */
+
+/**
+ * @event closing
+ * @param {OO.ui.Window} win Window that's being closed
+ * @param {Object} config Window closing information
+ */
+
+/**
+ * @event close
+ * @param {OO.ui.Window} win Window that's been closed
+ * @param {Object} config Window closing information
+ */
+
+/* Methods */
+
+/**
+ * Handle a window that's being opened.
+ *
+ * @method
+ * @param {OO.ui.Window} win Window that's being opened
+ * @param {Object} [config] Window opening information
+ * @fires opening
+ */
+OO.ui.WindowSet.prototype.onWindowOpening = function ( win, config ) {
+       if ( this.currentWindow && this.currentWindow !== win ) {
+               this.currentWindow.close();
+       }
+       this.currentWindow = win;
+       this.emit( 'opening', win, config );
+};
+
+/**
+ * Handle a window that's been opened.
+ *
+ * @method
+ * @param {OO.ui.Window} win Window that's been opened
+ * @param {Object} [config] Window opening information
+ * @fires open
+ */
+OO.ui.WindowSet.prototype.onWindowOpen = function ( win, config ) {
+       this.emit( 'open', win, config );
+};
+
+/**
+ * Handle a window that's being closed.
+ *
+ * @method
+ * @param {OO.ui.Window} win Window that's being closed
+ * @param {Object} [config] Window closing information
+ * @fires closing
+ */
+OO.ui.WindowSet.prototype.onWindowClosing = function ( win, config ) {
+       this.currentWindow = null;
+       this.emit( 'closing', win, config );
+};
+
+/**
+ * Handle a window that's been closed.
+ *
+ * @method
+ * @param {OO.ui.Window} win Window that's been closed
+ * @param {Object} [config] Window closing information
+ * @fires close
+ */
+OO.ui.WindowSet.prototype.onWindowClose = function ( win, config ) {
+       this.emit( 'close', win, config );
+};
+
+/**
+ * Get the current window.
+ *
+ * @method
+ * @returns {OO.ui.Window} Current window
+ */
+OO.ui.WindowSet.prototype.getCurrentWindow = function () {
+       return this.currentWindow;
+};
+
+/**
+ * Return a given window.
+ *
+ * @param {string} name Symbolic name of window
+ * @return {OO.ui.Window} Window with specified name
+ */
+OO.ui.WindowSet.prototype.getWindow = function ( name ) {
+       var win;
+
+       if ( !this.factory.lookup( name ) ) {
+               throw new Error( 'Unknown window: ' + name );
+       }
+       if ( !( name in this.windows ) ) {
+               win = this.windows[name] = this.factory.create( name, this, { '$': this.$ } );
+               win.connect( this, {
+                       'opening': [ 'onWindowOpening', win ],
+                       'open': [ 'onWindowOpen', win ],
+                       'closing': [ 'onWindowClosing', win ],
+                       'close': [ 'onWindowClose', win ]
+               } );
+               this.$element.append( win.$element );
+               win.getFrame().load();
+       }
+       return this.windows[name];
+};
+/**
+ * Modal dialog box.
+ *
+ * @class
+ * @abstract
+ * @extends OO.ui.Window
+ *
+ * @constructor
+ * @param {OO.ui.WindowSet} windowSet Window set this dialog is part of
+ * @param {Object} [config] Configuration options
+ * @cfg {boolean} [footless] Hide foot
+ * @cfg {boolean} [small] Make the dialog small
+ */
+OO.ui.Dialog = function OoUiDialog( windowSet, config ) {
+       // Configuration initialization
+       config = config || {};
+
+       // Parent constructor
+       OO.ui.Window.call( this, windowSet, config );
+
+       // Properties
+       this.visible = false;
+       this.footless = !!config.footless;
+       this.small = !!config.small;
+       this.onWindowMouseWheelHandler = OO.ui.bind( this.onWindowMouseWheel, this );
+       this.onDocumentKeyDownHandler = OO.ui.bind( this.onDocumentKeyDown, this );
+
+       // Events
+       this.$element.on( 'mousedown', false );
+
+       // Initialization
+       this.$element.addClass( 'oo-ui-dialog' );
+};
+
+/* Inheritance */
+
+OO.inheritClass( OO.ui.Dialog, OO.ui.Window );
+
+/* Static Properties */
+
+/**
+ * Symbolic name of dialog.
+ *
+ * @abstract
+ * @static
+ * @property {string}
+ * @inheritable
+ */
+OO.ui.Dialog.static.name = '';
+
+/* Methods */
+
+/**
+ * Handle close button click events.
+ *
+ * @method
+ */
+OO.ui.Dialog.prototype.onCloseButtonClick = function () {
+       this.close( { 'action': 'cancel' } );
+};
+
+/**
+ * Handle window mouse wheel events.
+ *
+ * @method
+ * @param {jQuery.Event} e Mouse wheel event
+ */
+OO.ui.Dialog.prototype.onWindowMouseWheel = function () {
+       return false;
+};
+
+/**
+ * Handle document key down events.
+ *
+ * @method
+ * @param {jQuery.Event} e Key down event
+ */
+OO.ui.Dialog.prototype.onDocumentKeyDown = function ( e ) {
+       switch ( e.which ) {
+               case OO.ui.Keys.PAGEUP:
+               case OO.ui.Keys.PAGEDOWN:
+               case OO.ui.Keys.END:
+               case OO.ui.Keys.HOME:
+               case OO.ui.Keys.LEFT:
+               case OO.ui.Keys.UP:
+               case OO.ui.Keys.RIGHT:
+               case OO.ui.Keys.DOWN:
+                       // Prevent any key events that might cause scrolling
+                       return false;
+       }
+};
+
+/**
+ * Handle frame document key down events.
+ *
+ * @method
+ * @param {jQuery.Event} e Key down event
+ */
+OO.ui.Dialog.prototype.onFrameDocumentKeyDown = function ( e ) {
+       if ( e.which === OO.ui.Keys.ESCAPE ) {
+               this.close( { 'action': 'cancel' } );
+               return false;
+       }
+};
+
+/**
+ * @inheritdoc
+ */
+OO.ui.Dialog.prototype.initialize = function () {
+       // Parent method
+       OO.ui.Window.prototype.initialize.call( this );
+
+       // Properties
+       this.closeButton = new OO.ui.ButtonWidget( {
+               '$': this.$,
+               'frameless': true,
+               'icon': 'close',
+               'title': OO.ui.msg( 'ooui-dialog-action-close' )
+       } );
+
+       // Events
+       this.closeButton.connect( this, { 'click': 'onCloseButtonClick' } );
+       this.frame.$document.on( 'keydown', OO.ui.bind( this.onFrameDocumentKeyDown, this ) );
+
+       // Initialization
+       this.frame.$content.addClass( 'oo-ui-dialog-content' );
+       if ( this.footless ) {
+               this.frame.$content.addClass( 'oo-ui-dialog-content-footless' );
+       }
+       if ( this.small ) {
+               this.$frame.addClass( 'oo-ui-window-frame-small' );
+       }
+       this.closeButton.$element.addClass( 'oo-ui-window-closeButton' );
+       this.$head.append( this.closeButton.$element );
+};
+
+/**
+ * @inheritdoc
+ */
+OO.ui.Dialog.prototype.setup = function ( data ) {
+       // Parent method
+       OO.ui.Window.prototype.setup.call( this, data );
+
+       // Prevent scrolling in top-level window
+       this.$( window ).on( 'mousewheel', this.onWindowMouseWheelHandler );
+       this.$( document ).on( 'keydown', this.onDocumentKeyDownHandler );
+};
+
+/**
+ * @inheritdoc
+ */
+OO.ui.Dialog.prototype.teardown = function ( data ) {
+       // Parent method
+       OO.ui.Window.prototype.teardown.call( this, data );
+
+       // Allow scrolling in top-level window
+       this.$( window ).off( 'mousewheel', this.onWindowMouseWheelHandler );
+       this.$( document ).off( 'keydown', this.onDocumentKeyDownHandler );
+};
+
+/**
+ * @inheritdoc
+ */
+OO.ui.Dialog.prototype.close = function ( data ) {
+       if ( !this.opening && !this.closing && this.visible ) {
+               // Trigger transition
+               this.$element.addClass( 'oo-ui-dialog-closing' );
+               // Allow transition to complete before actually closing
+               setTimeout( OO.ui.bind( function () {
+                       this.$element.removeClass( 'oo-ui-dialog-closing' );
+                       // Parent method
+                       OO.ui.Window.prototype.close.call( this, data );
+               }, this ), 250 );
+       }
+};
+/**
+ * Container for elements.
+ *
+ * @class
+ * @abstract
+ * @extends OO.ui.Element
+ * @mixin OO.EventEmitter
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ */
+OO.ui.Layout = function OoUiLayout( config ) {
+       // Initialize config
+       config = config || {};
+
+       // Parent constructor
+       OO.ui.Element.call( this, config );
+
+       // Mixin constructors
+       OO.EventEmitter.call( this );
+
+       // Initialization
+       this.$element.addClass( 'oo-ui-layout' );
+};
+
+/* Inheritance */
+
+OO.inheritClass( OO.ui.Layout, OO.ui.Element );
+
+OO.mixinClass( OO.ui.Layout, OO.EventEmitter );
+/**
+ * User interface control.
+ *
+ * @class
+ * @abstract
+ * @extends OO.ui.Element
+ * @mixin OO.EventEmitter
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ * @cfg {boolean} [disabled=false] Disable
+ */
+OO.ui.Widget = function OoUiWidget( config ) {
+       // Initialize config
+       config = $.extend( { 'disabled': false }, config );
+
+       // Parent constructor
+       OO.ui.Element.call( this, config );
+
+       // Mixin constructors
+       OO.EventEmitter.call( this );
+
+       // Properties
+       this.disabled = null;
+       this.wasDisabled = null;
+
+       // Initialization
+       this.$element.addClass( 'oo-ui-widget' );
+       this.setDisabled( !!config.disabled );
+};
+
+/* Inheritance */
+
+OO.inheritClass( OO.ui.Widget, OO.ui.Element );
+
+OO.mixinClass( OO.ui.Widget, OO.EventEmitter );
+
+/* Events */
+
+/**
+ * @event disable
+ * @param {boolean} disabled Widget is disabled
+ */
+
+/* Methods */
+
+/**
+ * Check if the widget is disabled.
+ *
+ * @method
+ * @param {boolean} Button is disabled
+ */
+OO.ui.Widget.prototype.isDisabled = function () {
+       return this.disabled;
+};
+
+/**
+ * Update the disabled state, in case of changes in parent widget.
+ *
+ * @method
+ * @chainable
+ */
+OO.ui.Widget.prototype.updateDisabled = function () {
+       this.setDisabled( this.disabled );
+       return this;
+};
+
+/**
+ * Set the disabled state of the widget.
+ *
+ * This should probably change the widgets's appearance and prevent it from being used.
+ *
+ * @method
+ * @param {boolean} disabled Disable widget
+ * @chainable
+ */
+OO.ui.Widget.prototype.setDisabled = function ( disabled ) {
+       var isDisabled;
+
+       this.disabled = !!disabled;
+       isDisabled = this.isDisabled();
+       if ( isDisabled !== this.wasDisabled ) {
+               this.$element.toggleClass( 'oo-ui-widget-disabled', isDisabled );
+               this.emit( 'disable', isDisabled );
+       }
+       this.wasDisabled = isDisabled;
+       return this;
+};
+/**
+ * Element with a button.
+ *
+ * @class
+ * @abstract
+ *
+ * @constructor
+ * @param {jQuery} $button Button node, assigned to #$button
+ * @param {Object} [config] Configuration options
+ * @cfg {boolean} [frameless] Render button without a frame
+ * @cfg {number} [tabIndex] Button's tab index
+ */
+OO.ui.ButtonedElement = function OoUiButtonedElement( $button, config ) {
+       // Configuration initialization
+       config = config || {};
+
+       // Properties
+       this.$button = $button;
+       this.tabIndex = null;
+       this.active = false;
+       this.onMouseUpHandler = OO.ui.bind( this.onMouseUp, this );
+
+       // Events
+       this.$button.on( 'mousedown', OO.ui.bind( this.onMouseDown, this ) );
+
+       // Initialization
+       this.$element.addClass( 'oo-ui-buttonedElement' );
+       this.$button
+               .addClass( 'oo-ui-buttonedElement-button' )
+               .attr( 'role', 'button' )
+               .prop( 'tabIndex', config.tabIndex || 0 );
+       if ( config.frameless ) {
+               this.$element.addClass( 'oo-ui-buttonedElement-frameless' );
+       } else {
+               this.$element.addClass( 'oo-ui-buttonedElement-framed' );
+       }
+};
+
+/* Methods */
+
+/**
+ * Handles mouse down events.
+ *
+ * @method
+ * @param {jQuery.Event} e Mouse down event
+ */
+OO.ui.ButtonedElement.prototype.onMouseDown = function () {
+       this.tabIndex = this.$button.attr( 'tabIndex' );
+       // Remove the tab-index while the button is down to prevent the button from stealing focus
+       this.$button.removeAttr( 'tabIndex' );
+       this.getElementDocument().addEventListener( 'mouseup', this.onMouseUpHandler, true );
+};
+
+/**
+ * Handles mouse up events.
+ *
+ * @method
+ * @param {jQuery.Event} e Mouse up event
+ */
+OO.ui.ButtonedElement.prototype.onMouseUp = function () {
+       // Restore the tab-index after the button is up to restore the button's accesssibility
+       this.$button.attr( 'tabIndex', this.tabIndex );
+       this.getElementDocument().removeEventListener( 'mouseup', this.onMouseUpHandler, true );
+};
+
+/**
+ * Set active state.
+ *
+ * @method
+ * @param {boolean} [value] Make button active
+ * @chainable
+ */
+OO.ui.ButtonedElement.prototype.setActive = function ( value ) {
+       this.$element.toggleClass( 'oo-ui-buttonedElement-active', !!value );
+       return this;
+};
+/**
+ * Element that can be automatically clipped to visible boundaies.
+ *
+ * @class
+ * @abstract
+ *
+ * @constructor
+ * @param {jQuery} $clippable Nodes to clip, assigned to #$clippable
+ */
+OO.ui.ClippableElement = function OoUiClippableElement( $clippable ) {
+       // Properties
+       this.$clippable = $clippable;
+       this.clipping = false;
+       this.clipped = false;
+       this.$clippableContainer = null;
+       this.$clippableScroller = null;
+       this.$clippableWindow = null;
+       this.idealWidth = null;
+       this.idealHeight = null;
+       this.onClippableContainerScrollHandler = OO.ui.bind( this.clip, this );
+       this.onClippableWindowResizeHandler = OO.ui.bind( this.clip, this );
+
+       // Initialization
+       this.$clippable.addClass( 'oo-ui-clippableElement-clippable' );
+};
+
+/* Methods */
+
+/**
+ * Set clipping.
+ *
+ * @method
+ * @param {boolean} value Enable clipping
+ * @chainable
+ */
+OO.ui.ClippableElement.prototype.setClipping = function ( value ) {
+       value = !!value;
+
+       if ( this.clipping !== value ) {
+               this.clipping = value;
+               if ( this.clipping ) {
+                       this.$clippableContainer = this.$( this.getClosestScrollableElementContainer() );
+                       // If the clippable container is the body, we have to listen to scroll events and check
+                       // jQuery.scrollTop on the window because of browser inconsistencies
+                       this.$clippableScroller = this.$clippableContainer.is( 'body' ) ?
+                               this.$( OO.ui.Element.getWindow( this.$clippableContainer ) ) :
+                               this.$clippableContainer;
+                       this.$clippableScroller.on( 'scroll', this.onClippableContainerScrollHandler );
+                       this.$clippableWindow = this.$( this.getElementWindow() )
+                               .on( 'resize', this.onClippableWindowResizeHandler );
+                       // Initial clip after visible
+                       setTimeout( OO.ui.bind( this.clip, this ) );
+               } else {
+                       this.$clippableContainer = null;
+                       this.$clippableScroller.off( 'scroll', this.onClippableContainerScrollHandler );
+                       this.$clippableScroller = null;
+                       this.$clippableWindow.off( 'resize', this.onClippableWindowResizeHandler );
+                       this.$clippableWindow = null;
+               }
+       }
+
+       return this;
+};
+
+/**
+ * Check if the element will be clipped to fit the visible area of the nearest scrollable container.
+ *
+ * @method
+ * @return {boolean} Element will be clipped to the visible area
+ */
+OO.ui.ClippableElement.prototype.isClipping = function () {
+       return this.clipping;
+};
+
+/**
+ * Check if the bottom or right of the element is being clipped by the nearest scrollable container.
+ *
+ * @method
+ * @return {boolean} Part of the element is being clipped
+ */
+OO.ui.ClippableElement.prototype.isClipped = function () {
+       return this.clipped;
+};
+
+/**
+ * Set the ideal size.
+ *
+ * @method
+ * @param {number|string} [width] Width as a number of pixels or CSS string with unit suffix
+ * @param {number|string} [height] Height as a number of pixels or CSS string with unit suffix
+ */
+OO.ui.ClippableElement.prototype.setIdealSize = function ( width, height ) {
+       this.idealWidth = width;
+       this.idealHeight = height;
+};
+
+/**
+ * Clip element to visible boundaries and allow scrolling when needed.
+ *
+ * Element will be clipped the bottom or right of the element is within 10px of the edge of, or
+ * overlapped by, the visible area of the nearest scrollable container.
+ *
+ * @method
+ * @chainable
+ */
+OO.ui.ClippableElement.prototype.clip = function () {
+       if ( !this.clipping ) {
+               // this.$clippableContainer and this.$clippableWindow are null, so the below will fail
+               return this;
+       }
+
+       var buffer = 10,
+               cOffset = this.$clippable.offset(),
+               ccOffset = this.$clippableContainer.offset() || { 'top': 0, 'left': 0 },
+               ccHeight = this.$clippableContainer.innerHeight() - buffer,
+               ccWidth = this.$clippableContainer.innerWidth() - buffer,
+               scrollTop = this.$clippableScroller.scrollTop(),
+               scrollLeft = this.$clippableScroller.scrollLeft(),
+               desiredWidth = ( ccOffset.left + scrollLeft + ccWidth ) - cOffset.left,
+               desiredHeight = ( ccOffset.top + scrollTop + ccHeight ) - cOffset.top,
+               naturalWidth = this.$clippable.prop( 'scrollWidth' ),
+               naturalHeight = this.$clippable.prop( 'scrollHeight' ),
+               clipWidth = desiredWidth < naturalWidth,
+               clipHeight = desiredHeight < naturalHeight;
+
+       if ( clipWidth ) {
+               this.$clippable.css( { 'overflow-x': 'auto', 'width': desiredWidth } );
+       } else {
+               this.$clippable.css( { 'overflow-x': '', 'width': this.idealWidth || '' } );
+       }
+       if ( clipHeight ) {
+               this.$clippable.css( { 'overflow-y': 'auto', 'height': desiredHeight } );
+       } else {
+               this.$clippable.css( { 'overflow-y': '', 'height': this.idealHeight || '' } );
+       }
+
+       this.clipped = clipWidth || clipHeight;
+
+       return this;
+};
+/**
+ * Element with named flags, used for styling, that can be added, removed and listed and checked.
+ *
+ * @class
+ * @abstract
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ * @cfg {string[]} [flags=[]] Styling flags, e.g. 'primary', 'destructive' or 'constructive'
+ */
+OO.ui.FlaggableElement = function OoUiFlaggableElement( config ) {
+       // Config initialization
+       config = config || {};
+
+       // Properties
+       this.flags = {};
+
+       // Initialization
+       this.setFlags( config.flags );
+};
+
+/* Methods */
+
+/**
+ * Check if a flag is set.
+ *
+ * @method
+ * @param {string} flag Flag name to check
+ * @returns {boolean} Has flag
+ */
+OO.ui.FlaggableElement.prototype.hasFlag = function ( flag ) {
+       return flag in this.flags;
+};
+
+/**
+ * Get the names of all flags.
+ *
+ * @method
+ * @returns {string[]} flags Flag names
+ */
+OO.ui.FlaggableElement.prototype.getFlags = function () {
+       return Object.keys( this.flags );
+};
+
+/**
+ * Add one or more flags.
+ *
+ * @method
+ * @param {string[]|Object.<string, boolean>} flags List of flags to add, or list of set/remove
+ *  values, keyed by flag name
+ * @chainable
+ */
+OO.ui.FlaggableElement.prototype.setFlags = function ( flags ) {
+       var i, len, flag,
+               classPrefix = 'oo-ui-flaggableElement-';
+
+       if ( Array.isArray( flags ) ) {
+               for ( i = 0, len = flags.length; i < len; i++ ) {
+                       flag = flags[i];
+                       // Set
+                       this.flags[flag] = true;
+                       this.$element.addClass( classPrefix + flag );
+               }
+       } else if ( OO.isPlainObject( flags ) ) {
+               for ( flag in flags ) {
+                       if ( flags[flags] ) {
+                               // Set
+                               this.flags[flag] = true;
+                               this.$element.addClass( classPrefix + flag );
+                       } else {
+                               // Remove
+                               delete this.flags[flag];
+                               this.$element.removeClass( classPrefix + flag );
+                       }
+               }
+       }
+       return this;
+};
+/**
+ * Element containing a sequence of child elements.
+ *
+ * @class
+ * @abstract
+ *
+ * @constructor
+ * @param {jQuery} $group Container node, assigned to #$group
+ * @param {Object} [config] Configuration options
+ * @cfg {Object.<string,string>} [aggregations] Events to aggregate, keyed by item event name
+ */
+OO.ui.GroupElement = function OoUiGroupElement( $group, config ) {
+       // Configuration
+       config = config || {};
+
+       // Properties
+       this.$group = $group;
+       this.items = [];
+       this.$items = this.$( [] );
+       this.aggregate = !$.isEmptyObject( config.aggregations );
+       this.aggregations = config.aggregations || {};
+};
+
+/* Methods */
+
+/**
+ * Get items.
+ *
+ * @method
+ * @returns {OO.ui.Element[]} Items
+ */
+OO.ui.GroupElement.prototype.getItems = function () {
+       return this.items.slice( 0 );
+};
+
+/**
+ * Add items.
+ *
+ * @method
+ * @param {OO.ui.Element[]} items Item
+ * @param {number} [index] Index to insert items at
+ * @chainable
+ */
+OO.ui.GroupElement.prototype.addItems = function ( items, index ) {
+       var i, len, item, event, events, currentIndex,
+               $items = this.$( [] );
+
+       for ( i = 0, len = items.length; i < len; i++ ) {
+               item = items[i];
+
+               // Check if item exists then remove it first, effectively "moving" it
+               currentIndex = this.items.indexOf( item );
+               if ( currentIndex >= 0 ) {
+                       this.removeItems( [ item ] );
+                       // Adjust index to compensate for removal
+                       if ( currentIndex < index ) {
+                               index--;
+                       }
+               }
+               // Add the item
+               if ( this.aggregate ) {
+                       events = {};
+                       for ( event in this.aggregations ) {
+                               events[event] = [ 'emit', this.aggregations[event], item ];
+                       }
+                       item.connect( this, events );
+               }
+               item.setElementGroup( this );
+               $items = $items.add( item.$element );
+       }
+
+       if ( index === undefined || index < 0 || index >= this.items.length ) {
+               this.$group.append( $items );
+               this.items.push.apply( this.items, items );
+       } else if ( index === 0 ) {
+               this.$group.prepend( $items );
+               this.items.unshift.apply( this.items, items );
+       } else {
+               this.$items.eq( index ).before( $items );
+               this.items.splice.apply( this.items, [ index, 0 ].concat( items ) );
+       }
+
+       this.$items = this.$items.add( $items );
+
+       return this;
+};
+
+/**
+ * Remove items.
+ *
+ * Items will be detached, not removed, so they can be used later.
+ *
+ * @method
+ * @param {OO.ui.Element[]} items Items to remove
+ * @chainable
+ */
+OO.ui.GroupElement.prototype.removeItems = function ( items ) {
+       var i, len, item, index;
+
+       // Remove specific items
+       for ( i = 0, len = items.length; i < len; i++ ) {
+               item = items[i];
+               index = this.items.indexOf( item );
+               if ( index !== -1 ) {
+                       if ( this.aggregate ) {
+                               item.disconnect( this );
+                       }
+                       item.setElementGroup( null );
+                       this.items.splice( index, 1 );
+                       item.$element.detach();
+                       this.$items = this.$items.not( item.$element );
+               }
+       }
+
+       return this;
+};
+
+/**
+ * Clear all items.
+ *
+ * Items will be detached, not removed, so they can be used later.
+ *
+ * @method
+ * @chainable
+ */
+OO.ui.GroupElement.prototype.clearItems = function () {
+       var i, len, item;
+
+       // Remove all items
+       if ( this.aggregate ) {
+               for ( i = 0, len = this.items.length; i < len; i++ ) {
+                       item.disconnect( this );
+               }
+       }
+       item.setElementGroup( null );
+       this.items = [];
+       this.$items.detach();
+       this.$items = this.$( [] );
+};
+/**
+ * Element containing an icon.
+ *
+ * @class
+ * @abstract
+ *
+ * @constructor
+ * @param {jQuery} $icon Icon node, assigned to #$icon
+ * @param {Object} [config] Configuration options
+ * @cfg {Object|string} [icon=''] Symbolic icon name, or map of icon names keyed by language ID;
+ *  use the 'default' key to specify the icon to be used when there is no icon in the user's
+ *  language
+ */
+OO.ui.IconedElement = function OoUiIconedElement( $icon, config ) {
+       // Config intialization
+       config = config || {};
+
+       // Properties
+       this.$icon = $icon;
+       this.icon = null;
+
+       // Initialization
+       this.$icon.addClass( 'oo-ui-iconedElement-icon' );
+       this.setIcon( config.icon || this.constructor.static.icon );
+};
+
+/* Static Properties */
+
+OO.ui.IconedElement.static = {};
+
+/**
+ * Icon.
+ *
+ * Value should be the unique portion of an icon CSS class name, such as 'up' for 'oo-ui-icon-up'.
+ *
+ * For i18n purposes, this property can be an object containing a `default` icon name property and
+ * additional icon names keyed by language code.
+ *
+ * Example of i18n icon definition:
+ *     { 'default': 'bold-a', 'en': 'bold-b', 'de': 'bold-f' }
+ *
+ * @static
+ * @inheritable
+ * @property {Object|string} Symbolic icon name, or map of icon names keyed by language ID;
+ *  use the 'default' key to specify the icon to be used when there is no icon in the user's
+ *  language
+ */
+OO.ui.IconedElement.static.icon = null;
+
+/* Methods */
+
+/**
+ * Set icon.
+ *
+ * @method
+ * @param {Object|string} icon Symbolic icon name, or map of icon names keyed by language ID;
+ *  use the 'default' key to specify the icon to be used when there is no icon in the user's
+ *  language
+ * @chainable
+ */
+OO.ui.IconedElement.prototype.setIcon = function ( icon ) {
+       icon = OO.isPlainObject( icon ) ? OO.ui.getLocalValue( icon, null, 'default' ) : icon;
+
+       if ( this.icon ) {
+               this.$icon.removeClass( 'oo-ui-icon-' + this.icon );
+       }
+       if ( typeof icon === 'string' ) {
+               icon = icon.trim();
+               if ( icon.length ) {
+                       this.$icon.addClass( 'oo-ui-icon-' + icon );
+                       this.icon = icon;
+               }
+       }
+       this.$element.toggleClass( 'oo-ui-iconedElement', !!this.icon );
+
+       return this;
+};
+
+/**
+ * Get icon.
+ *
+ * @method
+ * @returns {string} Icon
+ */
+OO.ui.IconedElement.prototype.getIcon = function () {
+       return this.icon;
+};
+/**
+ * Element containing an indicator.
+ *
+ * @class
+ * @abstract
+ *
+ * @constructor
+ * @param {jQuery} $indicator Indicator node, assigned to #$indicator
+ * @param {Object} [config] Configuration options
+ * @cfg {string} [indicator] Symbolic indicator name
+ * @cfg {string} [indicatorTitle] Indicator title text or a function that return text
+ */
+OO.ui.IndicatedElement = function OoUiIndicatedElement( $indicator, config ) {
+       // Config intialization
+       config = config || {};
+
+       // Properties
+       this.$indicator = $indicator;
+       this.indicator = null;
+       this.indicatorLabel = null;
+
+       // Initialization
+       this.$indicator.addClass( 'oo-ui-indicatedElement-indicator' );
+       this.setIndicator( config.indicator || this.constructor.static.indicator );
+       this.setIndicatorTitle( config.indicatorTitle  || this.constructor.static.indicatorTitle );
+};
+
+/* Static Properties */
+
+OO.ui.IndicatedElement.static = {};
+
+/**
+ * indicator.
+ *
+ * @static
+ * @inheritable
+ * @property {string|null} Symbolic indicator name or null for no indicator
+ */
+OO.ui.IndicatedElement.static.indicator = null;
+
+/**
+ * Indicator title.
+ *
+ * @static
+ * @inheritable
+ * @property {string|Function|null} Indicator title text, a function that return text or null for no
+ *  indicator title
+ */
+OO.ui.IndicatedElement.static.indicatorTitle = null;
+
+/* Methods */
+
+/**
+ * Set indicator.
+ *
+ * @method
+ * @param {string|null} indicator Symbolic name of indicator to use or null for no indicator
+ * @chainable
+ */
+OO.ui.IndicatedElement.prototype.setIndicator = function ( indicator ) {
+       if ( this.indicator ) {
+               this.$indicator.removeClass( 'oo-ui-indicator-' + this.indicator );
+               this.indicator = null;
+       }
+       if ( typeof indicator === 'string' ) {
+               indicator = indicator.trim();
+               if ( indicator.length ) {
+                       this.$indicator.addClass( 'oo-ui-indicator-' + indicator );
+                       this.indicator = indicator;
+               }
+       }
+       this.$element.toggleClass( 'oo-ui-indicatedElement', !!this.indicator );
+
+       return this;
+};
+
+/**
+ * Set indicator label.
+ *
+ * @method
+ * @param {string|Function|null} indicator Indicator title text, a function that return text or null
+ *  for no indicator title
+ * @chainable
+ */
+OO.ui.IndicatedElement.prototype.setIndicatorTitle = function ( indicatorTitle ) {
+       this.indicatorTitle = indicatorTitle = OO.ui.resolveMsg( indicatorTitle );
+
+       if ( typeof indicatorTitle === 'string' && indicatorTitle.length ) {
+               this.$indicator.attr( 'title', indicatorTitle );
+       } else {
+               this.$indicator.removeAttr( 'title' );
+       }
+
+       return this;
+};
+
+/**
+ * Get indicator.
+ *
+ * @method
+ * @returns {string} title Symbolic name of indicator
+ */
+OO.ui.IndicatedElement.prototype.getIndicator = function () {
+       return this.indicator;
+};
+
+/**
+ * Get indicator title.
+ *
+ * @method
+ * @returns {string} Indicator title text
+ */
+OO.ui.IndicatedElement.prototype.getIndicatorTitle = function () {
+       return this.indicatorTitle;
+};
+/**
+ * Element containing a label.
+ *
+ * @class
+ * @abstract
+ *
+ * @constructor
+ * @param {jQuery} $label Label node, assigned to #$label
+ * @param {Object} [config] Configuration options
+ * @cfg {jQuery|string|Function} [label] Label nodes, text or a function that returns nodes or text
+ */
+OO.ui.LabeledElement = function OoUiLabeledElement( $label, config ) {
+       // Config intialization
+       config = config || {};
+
+       // Properties
+       this.$label = $label;
+       this.label = null;
+
+       // Initialization
+       this.$label.addClass( 'oo-ui-labeledElement-label' );
+       this.setLabel( config.label || this.constructor.static.label );
+};
+
+/* Static Properties */
+
+OO.ui.LabeledElement.static = {};
+
+/**
+ * Label.
+ *
+ * @static
+ * @inheritable
+ * @property {string|Function|null} Label text; a function that returns a nodes or text; or null for
+ *  no label
+ */
+OO.ui.LabeledElement.static.label = null;
+
+/* Methods */
+
+/**
+ * Set the label.
+ *
+ * @method
+ * @param {jQuery|string|Function|null} label Label nodes; text; a function that retuns nodes or
+ *  text; or null for no label
+ * @chainable
+ */
+OO.ui.LabeledElement.prototype.setLabel = function ( label ) {
+       var empty = false;
+
+       this.label = label = OO.ui.resolveMsg( label ) || null;
+       if ( typeof label === 'string' && label.trim() ) {
+               this.$label.text( label );
+       } else if ( label instanceof jQuery ) {
+               this.$label.empty().append( label );
+       } else {
+               this.$label.empty();
+               empty = true;
+       }
+       this.$element.toggleClass( 'oo-ui-labeledElement', !empty );
+       this.$label.css( 'display', empty ? 'none' : '' );
+
+       return this;
+};
+
+/**
+ * Get the label.
+ *
+ * @method
+ * @returns {jQuery|string|Function|null} label Label nodes; text; a function that returns nodes or
+ *  text; or null for no label
+ */
+OO.ui.LabeledElement.prototype.getLabel = function () {
+       return this.label;
+};
+
+/**
+ * Fit the label.
+ *
+ * @method
+ * @chainable
+ */
+OO.ui.LabeledElement.prototype.fitLabel = function () {
+       if ( this.$label.autoEllipsis ) {
+               this.$label.autoEllipsis( { 'hasSpan': false, 'tooltip': true } );
+       }
+       return this;
+};
+/**
+ * Popuppable element.
+ *
+ * @class
+ * @abstract
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ * @cfg {number} [popupWidth=320] Width of popup
+ * @cfg {number} [popupHeight] Height of popup
+ * @cfg {Object} [popup] Configuration to pass to popup
+ */
+OO.ui.PopuppableElement = function OoUiPopuppableElement( config ) {
+       // Configuration initialization
+       config = $.extend( { 'popupWidth': 320 }, config );
+
+       // Properties
+       this.popup = new OO.ui.PopupWidget( $.extend(
+               { 'align': 'center', 'autoClose': true },
+               config.popup,
+               { '$': this.$, '$autoCloseIgnore': this.$element }
+       ) );
+       this.popupWidth = config.popupWidth;
+       this.popupHeight = config.popupHeight;
+};
+
+/* Methods */
+
+/**
+ * Get popup.
+ *
+ * @method
+ * @returns {OO.ui.PopupWidget} Popup widget
+ */
+OO.ui.PopuppableElement.prototype.getPopup = function () {
+       return this.popup;
+};
+
+/**
+ * Show popup.
+ *
+ * @method
+ */
+OO.ui.PopuppableElement.prototype.showPopup = function () {
+       this.popup.show().display( this.popupWidth, this.popupHeight );
+};
+
+/**
+ * Hide popup.
+ *
+ * @method
+ */
+OO.ui.PopuppableElement.prototype.hidePopup = function () {
+       this.popup.hide();
+};
+/**
+ * Element with a title.
+ *
+ * @class
+ * @abstract
+ *
+ * @constructor
+ * @param {jQuery} $label Titled node, assigned to #$titled
+ * @param {Object} [config] Configuration options
+ * @cfg {string|Function} [title] Title text or a function that returns text
+ */
+OO.ui.TitledElement = function OoUiTitledElement( $titled, config ) {
+       // Config intialization
+       config = config || {};
+
+       // Properties
+       this.$titled = $titled;
+       this.title = null;
+
+       // Initialization
+       this.setTitle( config.title || this.constructor.static.title );
+};
+
+/* Static Properties */
+
+OO.ui.TitledElement.static = {};
+
+/**
+ * Title.
+ *
+ * @static
+ * @inheritable
+ * @property {string|Function} Title text or a function that returns text
+ */
+OO.ui.TitledElement.static.title = null;
+
+/* Methods */
+
+/**
+ * Set title.
+ *
+ * @method
+ * @param {string|Function|null} title Title text, a function that returns text or null for no title
+ * @chainable
+ */
+OO.ui.TitledElement.prototype.setTitle = function ( title ) {
+       this.title = title = OO.ui.resolveMsg( title ) || null;
+
+       if ( typeof title === 'string' && title.length ) {
+               this.$titled.attr( 'title', title );
+       } else {
+               this.$titled.removeAttr( 'title' );
+       }
+
+       return this;
+};
+
+/**
+ * Get title.
+ *
+ * @method
+ * @returns {string} Title string
+ */
+OO.ui.TitledElement.prototype.getTitle = function () {
+       return this.title;
+};
+/**
+ * Generic toolbar tool.
+ *
+ * @class
+ * @abstract
+ * @extends OO.ui.Widget
+ * @mixins OO.ui.IconedElement
+ *
+ * @constructor
+ * @param {OO.ui.ToolGroup} toolGroup
+ * @param {Object} [config] Configuration options
+ * @cfg {string|Function} [title] Title text or a function that returns text
+ */
+OO.ui.Tool = function OoUiTool( toolGroup, config ) {
+       // Config intialization
+       config = config || {};
+
+       // Parent constructor
+       OO.ui.Widget.call( this, config );
+
+       // Mixin constructors
+       OO.ui.IconedElement.call( this, this.$( '<span>' ), config );
+
+       // Properties
+       this.toolGroup = toolGroup;
+       this.toolbar = this.toolGroup.getToolbar();
+       this.active = false;
+       this.$title = this.$( '<span>' );
+       this.$link = this.$( '<a>' );
+       this.title = null;
+
+       // Events
+       this.toolbar.connect( this, { 'updateState': 'onUpdateState' } );
+
+       // Initialization
+       this.$title.addClass( 'oo-ui-tool-title' );
+       this.$link
+               .addClass( 'oo-ui-tool-link' )
+               .append( this.$icon, this.$title );
+       this.$element
+               .data( 'oo-ui-tool', this )
+               .addClass(
+                       'oo-ui-tool ' + 'oo-ui-tool-name-' +
+                       this.constructor.static.name.replace( /^([^\/]+)\/([^\/]+).*$/, '$1-$2' )
+               )
+               .append( this.$link );
+       this.setTitle( config.title || this.constructor.static.title );
+};
+
+/* Inheritance */
+
+OO.inheritClass( OO.ui.Tool, OO.ui.Widget );
+
+OO.mixinClass( OO.ui.Tool, OO.ui.IconedElement );
+
+/* Events */
+
+/**
+ * @event select
+ */
+
+/* Static Properties */
+
+OO.ui.Tool.static.tagName = 'span';
+
+/**
+ * Symbolic name of tool.
+ *
+ * @abstract
+ * @static
+ * @property {string}
+ * @inheritable
+ */
+OO.ui.Tool.static.name = '';
+
+/**
+ * Tool group.
+ *
+ * @abstract
+ * @static
+ * @property {string}
+ * @inheritable
+ */
+OO.ui.Tool.static.group = '';
+
+/**
+ * Tool title.
+ *
+ * Title is used as a tooltip when the tool is part of a bar tool group, or a label when the tool
+ * is part of a list or menu tool group. If a trigger is associated with an action by the same name
+ * as the tool, a description of its keyboard shortcut for the appropriate platform will be
+ * appended to the title if the tool is part of a bar tool group.
+ *
+ * @abstract
+ * @static
+ * @property {string|Function} Title text or a function that returns text
+ * @inheritable
+ */
+OO.ui.Tool.static.title = '';
+
+/**
+ * Tool can be automatically added to tool groups.
+ *
+ * @static
+ * @property {boolean}
+ * @inheritable
+ */
+OO.ui.Tool.static.autoAdd = true;
+
+/**
+ * Check if this tool is compatible with given data.
+ *
+ * @method
+ * @static
+ * @inheritable
+ * @param {Mixed} data Data to check
+ * @returns {boolean} Tool can be used with data
+ */
+OO.ui.Tool.static.isCompatibleWith = function () {
+       return false;
+};
+
+/* Methods */
+
+/**
+ * Handle the toolbar state being updated.
+ *
+ * This is an abstract method that must be overridden in a concrete subclass.
+ *
+ * @abstract
+ * @method
+ */
+OO.ui.Tool.prototype.onUpdateState = function () {
+       throw new Error(
+               'OO.ui.Tool.onUpdateState not implemented in this subclass:' + this.constructor
+       );
+};
+
+/**
+ * Handle the tool being selected.
+ *
+ * This is an abstract method that must be overridden in a concrete subclass.
+ *
+ * @abstract
+ * @method
+ */
+OO.ui.Tool.prototype.onSelect = function () {
+       throw new Error(
+               'OO.ui.Tool.onSelect not implemented in this subclass:' + this.constructor
+       );
+};
+
+/**
+ * Check if the button is active.
+ *
+ * @method
+ * @param {boolean} Button is active
+ */
+OO.ui.Tool.prototype.isActive = function () {
+       return this.active;
+};
+
+/**
+ * Make the button appear active or inactive.
+ *
+ * @method
+ * @param {boolean} state Make button appear active
+ */
+OO.ui.Tool.prototype.setActive = function ( state ) {
+       this.active = !!state;
+       if ( this.active ) {
+               this.$element.addClass( 'oo-ui-tool-active' );
+       } else {
+               this.$element.removeClass( 'oo-ui-tool-active' );
+       }
+};
+
+/**
+ * Get the tool title.
+ *
+ * @method
+ * @param {string|Function} title Title text or a function that returns text
+ * @chainable
+ */
+OO.ui.Tool.prototype.setTitle = function ( title ) {
+       this.title = OO.ui.resolveMsg( title );
+       this.updateTitle();
+       return this;
+};
+
+/**
+ * Get the tool title.
+ *
+ * @method
+ * @returns {string} Title text
+ */
+OO.ui.Tool.prototype.getTitle = function () {
+       return this.title;
+};
+
+/**
+ * Get the tool's symbolic name.
+ *
+ * @method
+ * @returns {string} Symbolic name of tool
+ */
+OO.ui.Tool.prototype.getName = function () {
+       return this.constructor.static.name;
+};
+
+/**
+ * Update the title.
+ *
+ * @method
+ */
+OO.ui.Tool.prototype.updateTitle = function () {
+       var titleTooltips = this.toolGroup.constructor.static.titleTooltips,
+               accelTooltips = this.toolGroup.constructor.static.accelTooltips,
+               accel = this.toolbar.getToolAccelerator( this.constructor.static.name ),
+               tooltipParts = [];
+
+       this.$title.empty()
+               .text( this.title )
+               .append(
+                       this.$( '<span>' )
+                               .addClass( 'oo-ui-tool-accel' )
+                               .text( accel )
+               );
+
+       if ( titleTooltips && typeof this.title === 'string' && this.title.length ) {
+               tooltipParts.push( this.title );
+       }
+       if ( accelTooltips && typeof accel === 'string' && accel.length ) {
+               tooltipParts.push( accel );
+       }
+       if ( tooltipParts.length ) {
+               this.$link.attr( 'title', tooltipParts.join( ' ' ) );
+       } else {
+               this.$link.removeAttr( 'title' );
+       }
+};
+
+/**
+ * Destroy tool.
+ *
+ * @method
+ */
+OO.ui.Tool.prototype.destroy = function () {
+       this.toolbar.disconnect( this );
+       this.$element.remove();
+};
+/**
+ * Collection of tool groups.
+ *
+ * @class
+ * @extends OO.ui.Element
+ * @mixins OO.EventEmitter
+ * @mixins OO.ui.GroupElement
+ *
+ * @constructor
+ * @param {OO.Factory} toolFactory Factory for creating tools
+ * @param {Object} [options] Configuration options
+ * @cfg {boolean} [actions] Add an actions section opposite to the tools
+ * @cfg {boolean} [shadow] Add a shadow below the toolbar
+ */
+OO.ui.Toolbar = function OoUiToolbar( toolFactory, options ) {
+       // Configuration initialization
+       options = options || {};
+
+       // Parent constructor
+       OO.ui.Element.call( this, options );
+
+       // Mixin constructors
+       OO.EventEmitter.call( this );
+       OO.ui.GroupElement.call( this, this.$( '<div>' ) );
+
+       // Properties
+       this.toolFactory = toolFactory;
+       this.groups = [];
+       this.tools = {};
+       this.$bar = this.$( '<div>' );
+       this.$actions = this.$( '<div>' );
+       this.initialized = false;
+
+       // Events
+       this.$element
+               .add( this.$bar ).add( this.$group ).add( this.$actions )
+               .on( 'mousedown', OO.ui.bind( this.onMouseDown, this ) );
+
+       // Initialization
+       this.$group.addClass( 'oo-ui-toolbar-tools' );
+       this.$bar.addClass( 'oo-ui-toolbar-bar' ).append( this.$group );
+       if ( options.actions ) {
+               this.$actions.addClass( 'oo-ui-toolbar-actions' );
+               this.$bar.append( this.$actions );
+       }
+       this.$bar.append( '<div style="clear:both"></div>' );
+       if ( options.shadow ) {
+               this.$bar.append( '<div class="oo-ui-toolbar-shadow"></div>' );
+       }
+       this.$element.addClass( 'oo-ui-toolbar' ).append( this.$bar );
+};
+
+/* Inheritance */
+
+OO.inheritClass( OO.ui.Toolbar, OO.ui.Element );
+
+OO.mixinClass( OO.ui.Toolbar, OO.EventEmitter );
+OO.mixinClass( OO.ui.Toolbar, OO.ui.GroupElement );
+
+/* Methods */
+
+/**
+ * Get the tool factory.
+ *
+ * @method
+ * @returns {OO.Factory} Tool factory
+ */
+OO.ui.Toolbar.prototype.getToolFactory = function () {
+       return this.toolFactory;
+};
+
+/**
+ * Handles mouse down events.
+ *
+ * @method
+ * @param {jQuery.Event} e Mouse down event
+ */
+OO.ui.Toolbar.prototype.onMouseDown = function ( e ) {
+       var $closestWidgetToEvent = this.$( e.target ).closest( '.oo-ui-widget' ),
+               $closestWidgetToToolbar = this.$element.closest( '.oo-ui-widget' );
+       if ( !$closestWidgetToEvent.length || $closestWidgetToEvent[0] === $closestWidgetToToolbar[0] ) {
+               return false;
+       }
+};
+
+/**
+ * Sets up handles and preloads required information for the toolbar to work.
+ * This must be called immediately after it is attached to a visible document.
+ */
+OO.ui.Toolbar.prototype.initialize = function () {
+       this.initialized = true;
+};
+
+/**
+ * Setup toolbar.
+ *
+ * Tools can be specified in the following ways:
+ *  - A specific tool: `{ 'name': 'tool-name' }` or `'tool-name'`
+ *  - All tools in a group: `{ 'group': 'group-name' }`
+ *  - All tools: `'*'` - Using this will make the group a list with a "More" label by default
+ *
+ * @method
+ * @param {Object.<string,Array>} groups List of tool group configurations
+ * @param {Array|string} [groups.include] Tools to include
+ * @param {Array|string} [groups.exclude] Tools to exclude
+ * @param {Array|string} [groups.promote] Tools to promote to the beginning
+ * @param {Array|string} [groups.demote] Tools to demote to the end
+ */
+OO.ui.Toolbar.prototype.setup = function ( groups ) {
+       var i, len, type, group,
+               items = [],
+               // TODO: Use a registry instead
+               defaultType = 'bar',
+               constructors = {
+                       'bar': OO.ui.BarToolGroup,
+                       'list': OO.ui.ListToolGroup,
+                       'menu': OO.ui.MenuToolGroup
+               };
+
+       // Cleanup previous groups
+       this.reset();
+
+       // Build out new groups
+       for ( i = 0, len = groups.length; i < len; i++ ) {
+               group = groups[i];
+               if ( group.include === '*' ) {
+                       // Apply defaults to catch-all groups
+                       if ( group.type === undefined ) {
+                               group.type = 'list';
+                       }
+                       if ( group.label === undefined ) {
+                               group.label = 'ooui-toolbar-more';
+                       }
+               }
+               type = constructors[group.type] ? group.type : defaultType;
+               items.push(
+                       new constructors[type]( this, $.extend( { '$': this.$ }, group ) )
+               );
+       }
+       this.addItems( items );
+};
+
+/**
+ * Remove all tools and groups from the toolbar.
+ */
+OO.ui.Toolbar.prototype.reset = function () {
+       var i, len;
+
+       this.groups = [];
+       this.tools = {};
+       for ( i = 0, len = this.items.length; i < len; i++ ) {
+               this.items[i].destroy();
+       }
+       this.clearItems();
+};
+
+/**
+ * Destroys toolbar, removing event handlers and DOM elements.
+ *
+ * Call this whenever you are done using a toolbar.
+ */
+OO.ui.Toolbar.prototype.destroy = function () {
+       this.reset();
+       this.$element.remove();
+};
+
+/**
+ * Check if tool has not been used yet.
+ *
+ * @param {string} name Symbolic name of tool
+ * @return {boolean} Tool is available
+ */
+OO.ui.Toolbar.prototype.isToolAvailable = function ( name ) {
+       return !this.tools[name];
+};
+
+/**
+ * Prevent tool from being used again.
+ *
+ * @param {OO.ui.Tool} tool Tool to reserve
+ */
+OO.ui.Toolbar.prototype.reserveTool = function ( tool ) {
+       this.tools[tool.getName()] = tool;
+};
+
+/**
+ * Allow tool to be used again.
+ *
+ * @param {OO.ui.Tool} tool Tool to release
+ */
+OO.ui.Toolbar.prototype.releaseTool = function ( tool ) {
+       delete this.tools[tool.getName()];
+};
+
+/**
+ * Get accelerator label for tool.
+ *
+ * This is a stub that should be overridden to provide access to accelerator information.
+ *
+ * @param {string} name Symbolic name of tool
+ * @returns {string|undefined} Tool accelerator label if available
+ */
+OO.ui.Toolbar.prototype.getToolAccelerator = function () {
+       return undefined;
+};
+/**
+ * Factory for tools.
+ *
+ * @class
+ * @extends OO.Factory
+ * @constructor
+ */
+OO.ui.ToolFactory = function OoUiToolFactory() {
+       // Parent constructor
+       OO.Factory.call( this );
+};
+
+/* Inheritance */
+
+OO.inheritClass( OO.ui.ToolFactory, OO.Factory );
+
+/* Methods */
+
+OO.ui.ToolFactory.prototype.getTools = function ( include, exclude, promote, demote ) {
+       var i, len, included, promoted, demoted,
+               auto = [],
+               used = {};
+
+       // Collect included and not excluded tools
+       included = OO.simpleArrayDifference( this.extract( include ), this.extract( exclude ) );
+
+       // Promotion
+       promoted = this.extract( promote, used );
+       demoted = this.extract( demote, used );
+
+       // Auto
+       for ( i = 0, len = included.length; i < len; i++ ) {
+               if ( !used[included[i]] ) {
+                       auto.push( included[i] );
+               }
+       }
+
+       return promoted.concat( auto ).concat( demoted );
+};
+
+/**
+ * Get a flat list of names from a list of names or groups.
+ *
+ * Tools can be specified in the following ways:
+ *  - A specific tool: `{ 'name': 'tool-name' }` or `'tool-name'`
+ *  - All tools in a group: `{ 'group': 'group-name' }`
+ *  - All tools: `'*'`
+ *
+ * @private
+ * @param {Array|string} collection List of tools
+ * @param {Object} [used] Object with names that should be skipped as properties; extracted
+ *   names will be added as properties
+ * @return {string[]} List of extracted names
+ */
+OO.ui.ToolFactory.prototype.extract = function ( collection, used ) {
+       var i, len, item, name, tool,
+               names = [];
+
+       if ( collection === '*' ) {
+               for ( name in this.registry ) {
+                       tool = this.registry[name];
+                       if (
+                               // Only add tools by group name when auto-add is enabled
+                               tool.static.autoAdd &&
+                               // Exclude already used tools
+                               ( !used || !used[name] )
+                       ) {
+                               names.push( name );
+                               if ( used ) {
+                                       used[name] = true;
+                               }
+                       }
+               }
+       } else if ( Array.isArray( collection ) ) {
+               for ( i = 0, len = collection.length; i < len; i++ ) {
+                       item = collection[i];
+                       // Allow plain strings as shorthand for named tools
+                       if ( typeof item === 'string' ) {
+                               item = { 'name': item };
+                       }
+                       if ( OO.isPlainObject( item ) ) {
+                               if ( item.group ) {
+                                       for ( name in this.registry ) {
+                                               tool = this.registry[name];
+                                               if (
+                                                       // Include tools with matching group
+                                                       tool.static.group === item.group &&
+                                                       // Only add tools by group name when auto-add is enabled
+                                                       tool.static.autoAdd &&
+                                                       // Exclude already used tools
+                                                       ( !used || !used[name] )
+                                               ) {
+                                                       names.push( name );
+                                                       if ( used ) {
+                                                               used[name] = true;
+                                                       }
+                                               }
+                                       }
+                               }
+                               // Include tools with matching name and exclude already used tools
+                               else if ( item.name && ( !used || !used[item.name] ) ) {
+                                       names.push( item.name );
+                                       if ( used ) {
+                                               used[item.name] = true;
+                                       }
+                               }
+                       }
+               }
+       }
+       return names;
+};
+/**
+ * Collection of tools.
+ *
+ * @class
+ * @abstract
+ * @extends OO.ui.Widget
+ * @mixins OO.ui.GroupElement
+ *
+ * Tools can be specified in the following ways:
+ *  - A specific tool: `{ 'name': 'tool-name' }` or `'tool-name'`
+ *  - All tools in a group: `{ 'group': 'group-name' }`
+ *  - All tools: `'*'`
+ *
+ * @constructor
+ * @param {OO.ui.Toolbar} toolbar
+ * @param {Object} [config] Configuration options
+ * @cfg {Array|string} [include=[]] List of tools to include
+ * @cfg {Array|string} [exclude=[]] List of tools to exclude
+ * @cfg {Array|string} [promote=[]] List of tools to promote to the beginning
+ * @cfg {Array|string} [demote=[]] List of tools to demote to the end
+ */
+OO.ui.ToolGroup = function OoUiToolGroup( toolbar, config ) {
+       // Configuration initialization
+       config = config || {};
+
+       // Parent constructor
+       OO.ui.Widget.call( this, config );
+
+       // Mixin constructors
+       OO.ui.GroupElement.call( this, this.$( '<div>' ) );
+
+       // Properties
+       this.toolbar = toolbar;
+       this.tools = {};
+       this.pressed = null;
+       this.include = config.include || [];
+       this.exclude = config.exclude || [];
+       this.promote = config.promote || [];
+       this.demote = config.demote || [];
+       this.onCapturedMouseUpHandler = OO.ui.bind( this.onCapturedMouseUp, this );
+
+       // Events
+       this.$element.on( {
+               'mousedown': OO.ui.bind( this.onMouseDown, this ),
+               'mouseup': OO.ui.bind( this.onMouseUp, this ),
+               'mouseover': OO.ui.bind( this.onMouseOver, this ),
+               'mouseout': OO.ui.bind( this.onMouseOut, this )
+       } );
+       this.toolbar.getToolFactory().connect( this, { 'register': 'onToolFactoryRegister' } );
+
+       // Initialization
+       this.$group.addClass( 'oo-ui-toolGroup-tools' );
+       this.$element
+               .addClass( 'oo-ui-toolGroup' )
+               .append( this.$group );
+       this.populate();
+};
+
+/* Inheritance */
+
+OO.inheritClass( OO.ui.ToolGroup, OO.ui.Widget );
+
+OO.mixinClass( OO.ui.ToolGroup, OO.ui.GroupElement );
+
+/* Events */
+
+/**
+ * @event update
+ */
+
+/* Static Properties */
+
+/**
+ * Show labels in tooltips.
+ *
+ * @static
+ * @property {boolean}
+ * @inheritable
+ */
+OO.ui.ToolGroup.static.titleTooltips = false;
+
+/**
+ * Show acceleration labels in tooltips.
+ *
+ * @static
+ * @property {boolean}
+ * @inheritable
+ */
+OO.ui.ToolGroup.static.accelTooltips = false;
+
+/* Methods */
+
+/**
+ * Handle mouse down events.
+ *
+ * @method
+ * @param {jQuery.Event} e Mouse down event
+ */
+OO.ui.ToolGroup.prototype.onMouseDown = function ( e ) {
+       if ( !this.disabled && e.which === 1 ) {
+               this.pressed = this.getTargetTool( e );
+               if ( this.pressed ) {
+                       this.pressed.setActive( true );
+                       this.getElementDocument().addEventListener(
+                               'mouseup', this.onCapturedMouseUpHandler, true
+                       );
+                       return false;
+               }
+       }
+};
+
+/**
+ * Handle captured mouse up events.
+ *
+ * @method
+ * @param {Event} e Mouse up event
+ */
+OO.ui.ToolGroup.prototype.onCapturedMouseUp = function ( e ) {
+       this.getElementDocument().removeEventListener( 'mouseup', this.onCapturedMouseUpHandler, true );
+       // onMouseUp may be called a second time, depending on where the mouse is when the button is
+       // released, but since `this.pressed` will no longer be true, the second call will be ignored.
+       this.onMouseUp( e );
+};
+
+/**
+ * Handle mouse up events.
+ *
+ * @method
+ * @param {jQuery.Event} e Mouse up event
+ */
+OO.ui.ToolGroup.prototype.onMouseUp = function ( e ) {
+       var tool = this.getTargetTool( e );
+
+       if ( !this.disabled && e.which === 1 && this.pressed && this.pressed === tool ) {
+               this.pressed.onSelect();
+       }
+
+       this.pressed = null;
+       return false;
+};
+
+/**
+ * Handle mouse over events.
+ *
+ * @method
+ * @param {jQuery.Event} e Mouse over event
+ */
+OO.ui.ToolGroup.prototype.onMouseOver = function ( e ) {
+       var tool = this.getTargetTool( e );
+
+       if ( this.pressed && this.pressed === tool ) {
+               this.pressed.setActive( true );
+       }
+};
+
+/**
+ * Handle mouse out events.
+ *
+ * @method
+ * @param {jQuery.Event} e Mouse out event
+ */
+OO.ui.ToolGroup.prototype.onMouseOut = function ( e ) {
+       var tool = this.getTargetTool( e );
+
+       if ( this.pressed && this.pressed === tool ) {
+               this.pressed.setActive( false );
+       }
+};
+
+/**
+ * Get the closest tool to a jQuery.Event.
+ *
+ * Only tool links are considered, which prevents other elements in the tool such as popups from
+ * triggering tool group interactions.
+ *
+ * @method
+ * @private
+ * @param {jQuery.Event} e
+ * @returns {OO.ui.Tool|null} Tool, `null` if none was found
+ */
+OO.ui.ToolGroup.prototype.getTargetTool = function ( e ) {
+       var tool,
+               $item = this.$( e.target ).closest( '.oo-ui-tool-link' );
+
+       if ( $item.length ) {
+               tool = $item.parent().data( 'oo-ui-tool' );
+       }
+
+       return tool && !tool.isDisabled() ? tool : null;
+};
+
+/**
+ * Handle tool registry register events.
+ *
+ * If a tool is registered after the group is created, we must repopulate the list to account for:
+ * - a tool being added that may be included
+ * - a tool already included being overridden
+ *
+ * @param {string} name Symbolic name of tool
+ */
+OO.ui.ToolGroup.prototype.onToolFactoryRegister = function () {
+       this.populate();
+};
+
+/**
+ * Get the toolbar this group is in.
+ *
+ * @return {OO.ui.Toolbar} Toolbar of group
+ */
+OO.ui.ToolGroup.prototype.getToolbar = function () {
+       return this.toolbar;
+};
+
+/**
+ * Add and remove tools based on configuration.
+ *
+ * @method
+ */
+OO.ui.ToolGroup.prototype.populate = function () {
+       var i, len, name, tool,
+               toolFactory = this.toolbar.getToolFactory(),
+               names = {},
+               add = [],
+               remove = [],
+               list = this.toolbar.getToolFactory().getTools(
+                       this.include, this.exclude, this.promote, this.demote
+               );
+
+       // Build a list of needed tools
+       for ( i = 0, len = list.length; i < len; i++ ) {
+               name = list[i];
+               if (
+                       // Tool exists
+                       toolFactory.lookup( name ) &&
+                       // Tool is available or is already in this group
+                       ( this.toolbar.isToolAvailable( name ) || this.tools[name] )
+               ) {
+                       tool = this.tools[name];
+                       if ( !tool ) {
+                               // Auto-initialize tools on first use
+                               this.tools[name] = tool = toolFactory.create( name, this );
+                               tool.updateTitle();
+                       }
+                       this.toolbar.reserveTool( tool );
+                       add.push( tool );
+                       names[name] = true;
+               }
+       }
+       // Remove tools that are no longer needed
+       for ( name in this.tools ) {
+               if ( !names[name] ) {
+                       this.tools[name].destroy();
+                       this.toolbar.releaseTool( this.tools[name] );
+                       remove.push( this.tools[name] );
+                       delete this.tools[name];
+               }
+       }
+       if ( remove.length ) {
+               this.removeItems( remove );
+       }
+       // Update emptiness state
+       if ( add.length ) {
+               this.$element.removeClass( 'oo-ui-toolGroup-empty' );
+       } else {
+               this.$element.addClass( 'oo-ui-toolGroup-empty' );
+       }
+       // Re-add tools (moving existing ones to new locations)
+       this.addItems( add );
+};
+
+/**
+ * Destroy tool group.
+ *
+ * @method
+ */
+OO.ui.ToolGroup.prototype.destroy = function () {
+       var name;
+
+       this.clearItems();
+       this.toolbar.getToolFactory().disconnect( this );
+       for ( name in this.tools ) {
+               this.toolbar.releaseTool( this.tools[name] );
+               this.tools[name].disconnect( this ).destroy();
+               delete this.tools[name];
+       }
+       this.$element.remove();
+};
+/**
+ * Layout made of a fieldset and optional legend.
+ *
+ * @class
+ * @extends OO.ui.Layout
+ * @mixins OO.ui.LabeledElement
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ * @cfg {string} [icon] Symbolic icon name
+ */
+OO.ui.FieldsetLayout = function OoUiFieldsetLayout( config ) {
+       // Config initialization
+       config = config || {};
+
+       // Parent constructor
+       OO.ui.Layout.call( this, config );
+
+       // Mixin constructors
+       OO.ui.LabeledElement.call( this, this.$( '<legend>' ), config );
+
+       // Initialization
+       if ( config.icon ) {
+               this.$element.addClass( 'oo-ui-fieldsetLayout-decorated' );
+               this.$label.addClass( 'oo-ui-icon-' + config.icon );
+       }
+       this.$element.addClass( 'oo-ui-fieldsetLayout' );
+       if ( config.icon || config.label ) {
+               this.$element
+                       .addClass( 'oo-ui-fieldsetLayout-labeled' )
+                       .append( this.$label );
+       }
+};
+
+/* Inheritance */
+
+OO.inheritClass( OO.ui.FieldsetLayout, OO.ui.Layout );
+
+OO.mixinClass( OO.ui.FieldsetLayout, OO.ui.LabeledElement );
+
+/* Static Properties */
+
+OO.ui.FieldsetLayout.static.tagName = 'fieldset';
+/**
+ * Layout made of proportionally sized columns and rows.
+ *
+ * @class
+ * @extends OO.ui.Layout
+ *
+ * @constructor
+ * @param {OO.ui.PanelLayout[]} panels Panels in the grid
+ * @param {Object} [config] Configuration options
+ * @cfg {number[]} [widths] Widths of columns as ratios
+ * @cfg {number[]} [heights] Heights of columns as ratios
+ */
+OO.ui.GridLayout = function OoUiGridLayout( panels, config ) {
+       var i, len, widths;
+
+       // Config initialization
+       config = config || {};
+
+       // Parent constructor
+       OO.ui.Layout.call( this, config );
+
+       // Properties
+       this.panels = [];
+       this.widths = [];
+       this.heights = [];
+
+       // Initialization
+       this.$element.addClass( 'oo-ui-gridLayout' );
+       for ( i = 0, len = panels.length; i < len; i++ ) {
+               this.panels.push( panels[i] );
+               this.$element.append( panels[i].$element );
+       }
+       if ( config.widths || config.heights ) {
+               this.layout( config.widths || [1], config.heights || [1] );
+       } else {
+               // Arrange in columns by default
+               widths = [];
+               for ( i = 0, len = this.panels.length; i < len; i++ ) {
+                       widths[i] = 1;
+               }
+               this.layout( widths, [1] );
+       }
+};
+
+/* Inheritance */
+
+OO.inheritClass( OO.ui.GridLayout, OO.ui.Layout );
+
+/* Events */
+
+/**
+ * @event layout
+ */
+
+/**
+ * @event update
+ */
+
+/* Static Properties */
+
+OO.ui.GridLayout.static.tagName = 'div';
+
+/* Methods */
+
+/**
+ * Set grid dimensions.
+ *
+ * @method
+ * @param {number[]} widths Widths of columns as ratios
+ * @param {number[]} heights Heights of rows as ratios
+ * @fires layout
+ * @throws {Error} If grid is not large enough to fit all panels
+ */
+OO.ui.GridLayout.prototype.layout = function ( widths, heights ) {
+       var x, y,
+               xd = 0,
+               yd = 0,
+               cols = widths.length,
+               rows = heights.length;
+
+       // Verify grid is big enough to fit panels
+       if ( cols * rows < this.panels.length ) {
+               throw new Error( 'Grid is not large enough to fit ' + this.panels.length + 'panels' );
+       }
+
+       // Sum up denominators
+       for ( x = 0; x < cols; x++ ) {
+               xd += widths[x];
+       }
+       for ( y = 0; y < rows; y++ ) {
+               yd += heights[y];
+       }
+       // Store factors
+       this.widths = [];
+       this.heights = [];
+       for ( x = 0; x < cols; x++ ) {
+               this.widths[x] = widths[x] / xd;
+       }
+       for ( y = 0; y < rows; y++ ) {
+               this.heights[y] = heights[y] / yd;
+       }
+       // Synchronize view
+       this.update();
+       this.emit( 'layout' );
+};
+
+/**
+ * Update panel positions and sizes.
+ *
+ * @method
+ * @fires update
+ */
+OO.ui.GridLayout.prototype.update = function () {
+       var x, y, panel,
+               i = 0,
+               left = 0,
+               top = 0,
+               dimensions,
+               width = 0,
+               height = 0,
+               cols = this.widths.length,
+               rows = this.heights.length;
+
+       for ( y = 0; y < rows; y++ ) {
+               for ( x = 0; x < cols; x++ ) {
+                       panel = this.panels[i];
+                       width = this.widths[x];
+                       height = this.heights[y];
+                       dimensions = {
+                               'width': Math.round( width * 100 ) + '%',
+                               'height': Math.round( height * 100 ) + '%',
+                               'top': Math.round( top * 100 ) + '%'
+                       };
+                       // If RTL, reverse:
+                       if ( OO.ui.Element.getDir( this.$.context ) === 'rtl' ) {
+                               dimensions.right = Math.round( left * 100 ) + '%';
+                       } else {
+                               dimensions.left = Math.round( left * 100 ) + '%';
+                       }
+                       panel.$element.css( dimensions );
+                       i++;
+                       left += width;
+               }
+               top += height;
+               left = 0;
+       }
+
+       this.emit( 'update' );
+};
+
+/**
+ * Get a panel at a given position.
+ *
+ * The x and y position is affected by the current grid layout.
+ *
+ * @method
+ * @param {number} x Horizontal position
+ * @param {number} y Vertical position
+ * @returns {OO.ui.PanelLayout} The panel at the given postion
+ */
+OO.ui.GridLayout.prototype.getPanel = function ( x, y ) {
+       return this.panels[( x * this.widths.length ) + y];
+};
+/**
+ * Layout containing a series of pages.
+ *
+ * @class
+ * @extends OO.ui.Layout
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ * @cfg {boolean} [continuous=false] Show all pages, one after another
+ * @cfg {boolean} [autoFocus=false] Focus on the first focusable element when changing to a page
+ * @cfg {boolean} [outlined=false] Show an outline
+ * @cfg {boolean} [editable=false] Show controls for adding, removing and reordering pages
+ * @cfg {Object[]} [adders] List of adders for controls, each with name, icon and title properties
+ */
+OO.ui.BookletLayout = function OoUiBookletLayout( config ) {
+       // Initialize configuration
+       config = config || {};
+
+       // Parent constructor
+       OO.ui.Layout.call( this, config );
+
+       // Properties
+       this.currentPageName = null;
+       this.pages = {};
+       this.ignoreFocus = false;
+       this.stackLayout = new OO.ui.StackLayout( { '$': this.$, 'continuous': !!config.continuous } );
+       this.autoFocus = !!config.autoFocus;
+       this.outlined = !!config.outlined;
+       if ( this.outlined ) {
+               this.editable = !!config.editable;
+               this.adders = config.adders || null;
+               this.outlineControlsWidget = null;
+               this.outlineWidget = new OO.ui.OutlineWidget( { '$': this.$ } );
+               this.outlinePanel = new OO.ui.PanelLayout( { '$': this.$, 'scrollable': true } );
+               this.gridLayout = new OO.ui.GridLayout(
+                       [this.outlinePanel, this.stackLayout], { '$': this.$, 'widths': [1, 2] }
+               );
+               if ( this.editable ) {
+                       this.outlineControlsWidget = new OO.ui.OutlineControlsWidget(
+                               this.outlineWidget,
+                               { '$': this.$, 'adders': this.adders }
+                       );
+               }
+       }
+
+       // Events
+       this.stackLayout.connect( this, { 'set': 'onStackLayoutSet' } );
+       if ( this.outlined ) {
+               this.outlineWidget.connect( this, { 'select': 'onOutlineWidgetSelect' } );
+               // Event 'focus' does not bubble, but 'focusin' does
+               this.stackLayout.onDOMEvent( 'focusin', OO.ui.bind( this.onStackLayoutFocus, this ) );
+       }
+
+       // Initialization
+       this.$element.addClass( 'oo-ui-bookletLayout' );
+       this.stackLayout.$element.addClass( 'oo-ui-bookletLayout-stackLayout' );
+       if ( this.outlined ) {
+               this.outlinePanel.$element
+                       .addClass( 'oo-ui-bookletLayout-outlinePanel' )
+                       .append( this.outlineWidget.$element );
+               if ( this.editable ) {
+                       this.outlinePanel.$element
+                               .addClass( 'oo-ui-bookletLayout-outlinePanel-editable' )
+                               .append( this.outlineControlsWidget.$element );
+               }
+               this.$element.append( this.gridLayout.$element );
+       } else {
+               this.$element.append( this.stackLayout.$element );
+       }
+};
+
+/* Inheritance */
+
+OO.inheritClass( OO.ui.BookletLayout, OO.ui.Layout );
+
+/* Events */
+
+/**
+ * @event set
+ * @param {OO.ui.PageLayout} page Current page
+ */
+
+/**
+ * @event add
+ * @param {OO.ui.PageLayout[]} page Added pages
+ * @param {number} index Index pages were added at
+ */
+
+/**
+ * @event remove
+ * @param {OO.ui.PageLayout[]} pages Removed pages
+ */
+
+/* Methods */
+
+/**
+ * Handle stack layout focus.
+ *
+ * @method
+ * @param {jQuery.Event} e Focusin event
+ */
+OO.ui.BookletLayout.prototype.onStackLayoutFocus = function ( e ) {
+       var name, $target;
+
+       if ( this.ignoreFocus ) {
+               // Avoid recursion from programmatic focus trigger in #onStackLayoutSet
+               return;
+       }
+
+       $target = $( e.target ).closest( '.oo-ui-pageLayout' );
+       for ( name in this.pages ) {
+               if ( this.pages[ name ].$element[0] === $target[0] ) {
+                       this.setPage( name );
+                       break;
+               }
+       }
+};
+
+/**
+ * Handle stack layout set events.
+ *
+ * @method
+ * @param {OO.ui.PanelLayout|null} page The page panel that is now the current panel
+ */
+OO.ui.BookletLayout.prototype.onStackLayoutSet = function ( page ) {
+       if ( page ) {
+               page.scrollElementIntoView( { 'complete': OO.ui.bind( function () {
+                       this.ignoreFocus = true;
+                       if ( this.autoFocus ) {
+                               page.$element.find( ':input:first' ).focus();
+                       }
+                       this.ignoreFocus = false;
+               }, this ) } );
+       }
+};
+
+/**
+ * Handle outline widget select events.
+ *
+ * @method
+ * @param {OO.ui.OptionWidget|null} item Selected item
+ */
+OO.ui.BookletLayout.prototype.onOutlineWidgetSelect = function ( item ) {
+       if ( item ) {
+               this.setPage( item.getData() );
+       }
+};
+
+/**
+ * Check if booklet has an outline.
+ *
+ * @method
+ * @returns {boolean} Booklet is outlined
+ */
+OO.ui.BookletLayout.prototype.isOutlined = function () {
+       return this.outlined;
+};
+
+/**
+ * Check if booklet has editing controls.
+ *
+ * @method
+ * @returns {boolean} Booklet is outlined
+ */
+OO.ui.BookletLayout.prototype.isEditable = function () {
+       return this.editable;
+};
+
+/**
+ * Get the outline widget.
+ *
+ * @method
+ * @returns {OO.ui.OutlineWidget|null} Outline widget, or null if boolet has no outline
+ */
+OO.ui.BookletLayout.prototype.getOutline = function () {
+       return this.outlineWidget;
+};
+
+/**
+ * Get the outline controls widget. If the outline is not editable, null is returned.
+ *
+ * @method
+ * @returns {OO.ui.OutlineControlsWidget|null} The outline controls widget.
+ */
+OO.ui.BookletLayout.prototype.getOutlineControls = function () {
+       return this.outlineControlsWidget;
+};
+
+/**
+ * Get a page by name.
+ *
+ * @method
+ * @param {string} name Symbolic name of page
+ * @returns {OO.ui.PageLayout|undefined} Page, if found
+ */
+OO.ui.BookletLayout.prototype.getPage = function ( name ) {
+       return this.pages[name];
+};
+
+/**
+ * Get the current page name.
+ *
+ * @method
+ * @returns {string|null} Current page name
+ */
+OO.ui.BookletLayout.prototype.getPageName = function () {
+       return this.currentPageName;
+};
+
+/**
+ * Add a page to the layout.
+ *
+ * When pages are added with the same names as existing pages, the existing pages will be
+ * automatically removed before the new pages are added.
+ *
+ * @method
+ * @param {OO.ui.PageLayout[]} pages Pages to add
+ * @param {number} index Index to insert pages after
+ * @fires add
+ * @chainable
+ */
+OO.ui.BookletLayout.prototype.addPages = function ( pages, index ) {
+       var i, len, name, page,
+               items = [],
+               remove = [];
+
+       for ( i = 0, len = pages.length; i < len; i++ ) {
+               page = pages[i];
+               name = page.getName();
+               if ( name in this.pages ) {
+                       // Remove page with same name
+                       remove.push( this.pages[name] );
+               }
+               this.pages[page.getName()] = page;
+               if ( this.outlined ) {
+                       items.push( new OO.ui.BookletOutlineItemWidget( name, page, { '$': this.$ } ) );
+               }
+       }
+       if ( remove.length ) {
+               this.removePages( remove );
+       }
+
+       if ( this.outlined && items.length ) {
+               this.outlineWidget.addItems( items, index );
+               this.updateOutlineWidget();
+       }
+       this.stackLayout.addItems( pages, index );
+       this.emit( 'add', pages, index );
+
+       return this;
+};
+
+/**
+ * Remove a page from the layout.
+ *
+ * @method
+ * @fires remove
+ * @chainable
+ */
+OO.ui.BookletLayout.prototype.removePages = function ( pages ) {
+       var i, len, name, page,
+               items = [];
+
+       for ( i = 0, len = pages.length; i < len; i++ ) {
+               page = pages[i];
+               name = page.getName();
+               delete this.pages[name];
+               if ( this.outlined ) {
+                       items.push( this.outlineWidget.getItemFromData( name ) );
+               }
+       }
+       if ( this.outlined && items.length ) {
+               this.outlineWidget.removeItems( items );
+               this.updateOutlineWidget();
+       }
+       this.stackLayout.removeItems( pages );
+       this.emit( 'remove', pages );
+
+       return this;
+};
+
+/**
+ * Clear all pages from the layout.
+ *
+ * @method
+ * @fires remove
+ * @chainable
+ */
+OO.ui.BookletLayout.prototype.clearPages = function () {
+       var pages = this.stackLayout.getItems();
+
+       this.pages = {};
+       this.currentPageName = null;
+       if ( this.outlined ) {
+               this.outlineWidget.clearItems();
+       }
+       this.stackLayout.clearItems();
+
+       this.emit( 'remove', pages );
+
+       return this;
+};
+
+/**
+ * Set the current page by name.
+ *
+ * @method
+ * @fires set
+ * @param {string} name Symbolic name of page
+ */
+OO.ui.BookletLayout.prototype.setPage = function ( name ) {
+       var selectedItem,
+               page = this.pages[name];
+
+       if ( this.outlined ) {
+               selectedItem = this.outlineWidget.getSelectedItem();
+               if ( selectedItem && selectedItem.getData() !== name ) {
+                       this.outlineWidget.selectItem( this.outlineWidget.getItemFromData( name ) );
+               }
+       }
+
+       if ( page ) {
+               this.currentPageName = name;
+               this.stackLayout.setItem( page );
+               this.emit( 'set', page );
+       }
+};
+
+/**
+ * Call this after adding or removing items from the OutlineWidget.
+ *
+ * @method
+ * @chainable
+ */
+OO.ui.BookletLayout.prototype.updateOutlineWidget = function () {
+       // Auto-select first item when nothing is selected anymore
+       if ( !this.outlineWidget.getSelectedItem() ) {
+               this.outlineWidget.selectItem( this.outlineWidget.getFirstSelectableItem() );
+       }
+
+       return this;
+};
+/**
+ * Layout that expands to cover the entire area of its parent, with optional scrolling and padding.
+ *
+ * @class
+ * @extends OO.ui.Layout
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ * @cfg {boolean} [scrollable] Allow vertical scrolling
+ * @cfg {boolean} [padded] Pad the content from the edges
+ */
+OO.ui.PanelLayout = function OoUiPanelLayout( config ) {
+       // Config initialization
+       config = config || {};
+
+       // Parent constructor
+       OO.ui.Layout.call( this, config );
+
+       // Initialization
+       this.$element.addClass( 'oo-ui-panelLayout' );
+       if ( config.scrollable ) {
+               this.$element.addClass( 'oo-ui-panelLayout-scrollable' );
+       }
+
+       if ( config.padded ) {
+               this.$element.addClass( 'oo-ui-panelLayout-padded' );
+       }
+
+       // Add directionality class:
+       this.$element.addClass( 'oo-ui-' + OO.ui.Element.getDir( this.$.context ) );
+};
+
+/* Inheritance */
+
+OO.inheritClass( OO.ui.PanelLayout, OO.ui.Layout );
+/**
+ * Page within an OO.ui.BookletLayout.
+ *
+ * @class
+ * @extends OO.ui.PanelLayout
+ *
+ * @constructor
+ * @param {string} name Unique symbolic name of page
+ * @param {Object} [config] Configuration options
+ * @param {string} [icon=''] Symbolic name of icon to display in outline
+ * @param {string} [indicator=''] Symbolic name of indicator to display in outline
+ * @param {string} [indicatorTitle=''] Description of indicator meaning to display in outline
+ * @param {string} [label=''] Label to display in outline
+ * @param {number} [level=0] Indentation level of item in outline
+ * @param {boolean} [movable=false] Page should be movable using outline controls
+ */
+OO.ui.PageLayout = function OoUiPageLayout( name, config ) {
+       // Configuration initialization
+       config = $.extend( { 'scrollable': true }, config );
+
+       // Parent constructor
+       OO.ui.PanelLayout.call( this, config );
+
+       // Properties
+       this.name = name;
+       this.icon = config.icon || '';
+       this.indicator = config.indicator || '';
+       this.indicatorTitle = OO.ui.resolveMsg( config.indicatorTitle ) || '';
+       this.label = OO.ui.resolveMsg( config.label ) || '';
+       this.level = config.level || 0;
+       this.movable = !!config.movable;
+
+       // Initialization
+       this.$element.addClass( 'oo-ui-pageLayout' );
+};
+
+/* Inheritance */
+
+OO.inheritClass( OO.ui.PageLayout, OO.ui.PanelLayout );
+
+/* Methods */
+
+/**
+ * Get page name.
+ *
+ * @returns {string} Symbolic name of page
+ */
+OO.ui.PageLayout.prototype.getName = function () {
+       return this.name;
+};
+
+/**
+ * Get page icon.
+ *
+ * @returns {string} Symbolic name of icon
+ */
+OO.ui.PageLayout.prototype.getIcon = function () {
+       return this.icon;
+};
+
+/**
+ * Get page indicator.
+ *
+ * @returns {string} Symbolic name of indicator
+ */
+OO.ui.PageLayout.prototype.getIndicator = function () {
+       return this.indicator;
+};
+
+/**
+ * Get page indicator label.
+ *
+ * @returns {string} Description of indicator meaning
+ */
+OO.ui.PageLayout.prototype.getIndicatorTitle = function () {
+       return this.indicatorTitle;
+};
+
+/**
+ * Get page label.
+ *
+ * @returns {string} Label text
+ */
+OO.ui.PageLayout.prototype.getLabel = function () {
+       return this.label;
+};
+
+/**
+ * Get outline item indentation level.
+ *
+ * @returns {number} Indentation level
+ */
+OO.ui.PageLayout.prototype.getLevel = function () {
+       return this.level;
+};
+
+/**
+ * Check if page is movable using outline controls.
+ *
+ * @returns {boolean} Page is movable
+ */
+OO.ui.PageLayout.prototype.isMovable = function () {
+       return this.movable;
+};
+/**
+ * Layout containing a series of mutually exclusive pages.
+ *
+ * @class
+ * @extends OO.ui.PanelLayout
+ * @mixins OO.ui.GroupElement
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ * @cfg {boolean} [continuous=false] Show all pages, one after another
+ * @cfg {string} [icon=''] Symbolic icon name
+ */
+OO.ui.StackLayout = function OoUiStackLayout( config ) {
+       // Config initialization
+       config = $.extend( { 'scrollable': true }, config );
+
+       // Parent constructor
+       OO.ui.PanelLayout.call( this, config );
+
+       // Mixin constructors
+       OO.ui.GroupElement.call( this, this.$element, config );
+
+       // Properties
+       this.currentItem = null;
+       this.continuous = !!config.continuous;
+
+       // Initialization
+       this.$element.addClass( 'oo-ui-stackLayout' );
+       if ( this.continuous ) {
+               this.$element.addClass( 'oo-ui-stackLayout-continuous' );
+       }
+};
+
+/* Inheritance */
+
+OO.inheritClass( OO.ui.StackLayout, OO.ui.PanelLayout );
+
+OO.mixinClass( OO.ui.StackLayout, OO.ui.GroupElement );
+
+/* Events */
+
+/**
+ * @event set
+ * @param {OO.ui.PanelLayout|null} [item] Current item
+ */
+
+/* Methods */
+
+/**
+ * Add items.
+ *
+ * Adding an existing item (by value) will move it.
+ *
+ * @method
+ * @param {OO.ui.PanelLayout[]} items Items to add
+ * @param {number} [index] Index to insert items after
+ * @chainable
+ */
+OO.ui.StackLayout.prototype.addItems = function ( items, index ) {
+       OO.ui.GroupElement.prototype.addItems.call( this, items, index );
+
+       if ( !this.currentItem && items.length ) {
+               this.setItem( items[0] );
+       }
+
+       return this;
+};
+
+/**
+ * Remove items.
+ *
+ * Items will be detached, not removed, so they can be used later.
+ *
+ * @method
+ * @param {OO.ui.PanelLayout[]} items Items to remove
+ * @chainable
+ */
+OO.ui.StackLayout.prototype.removeItems = function ( items ) {
+       OO.ui.GroupElement.prototype.removeItems.call( this, items );
+       if ( items.indexOf( this.currentItem ) !== -1 ) {
+               this.currentItem = null;
+               if ( !this.currentItem && this.items.length ) {
+                       this.setItem( this.items[0] );
+               }
+       }
+
+       return this;
+};
+
+/**
+ * Clear all items.
+ *
+ * Items will be detached, not removed, so they can be used later.
+ *
+ * @method
+ * @chainable
+ */
+OO.ui.StackLayout.prototype.clearItems = function () {
+       this.currentItem = null;
+       OO.ui.GroupElement.prototype.clearItems.call( this );
+
+       return this;
+};
+
+/**
+ * Show item.
+ *
+ * Any currently shown item will be hidden.
+ *
+ * @method
+ * @param {OO.ui.PanelLayout} item Item to show
+ * @chainable
+ */
+OO.ui.StackLayout.prototype.setItem = function ( item ) {
+       if ( !this.continuous ) {
+               this.$items.css( 'display', '' );
+       }
+       if ( this.items.indexOf( item ) !== -1 ) {
+               if ( !this.continuous ) {
+                       item.$element.css( 'display', 'block' );
+               }
+       } else {
+               item = null;
+       }
+       this.currentItem = item;
+       this.emit( 'set', item );
+
+       return this;
+};
+/**
+ * Horizontal bar layout of tools as icon buttons.
+ *
+ * @class
+ * @abstract
+ * @extends OO.ui.ToolGroup
+ *
+ * @constructor
+ * @param {OO.ui.Toolbar} toolbar
+ * @param {Object} [config] Configuration options
+ */
+OO.ui.BarToolGroup = function OoUiBarToolGroup( toolbar, config ) {
+       // Parent constructor
+       OO.ui.ToolGroup.call( this, toolbar, config );
+
+       // Initialization
+       this.$element.addClass( 'oo-ui-barToolGroup' );
+};
+
+/* Inheritance */
+
+OO.inheritClass( OO.ui.BarToolGroup, OO.ui.ToolGroup );
+
+/* Static Properties */
+
+OO.ui.BarToolGroup.static.titleTooltips = true;
+
+OO.ui.BarToolGroup.static.accelTooltips = true;
+/**
+ * Popup list of tools with an icon and optional label.
+ *
+ * @class
+ * @abstract
+ * @extends OO.ui.ToolGroup
+ * @mixins OO.ui.IconedElement
+ * @mixins OO.ui.IndicatedElement
+ * @mixins OO.ui.LabeledElement
+ * @mixins OO.ui.TitledElement
+ * @mixins OO.ui.ClippableElement
+ *
+ * @constructor
+ * @param {OO.ui.Toolbar} toolbar
+ * @param {Object} [config] Configuration options
+ */
+OO.ui.PopupToolGroup = function OoUiPopupToolGroup( toolbar, config ) {
+       // Configuration initialization
+       config = config || {};
+
+       // Parent constructor
+       OO.ui.ToolGroup.call( this, toolbar, config );
+
+       // Mixin constructors
+       OO.ui.IconedElement.call( this, this.$( '<span>' ), config );
+       OO.ui.IndicatedElement.call( this, this.$( '<span>' ), config );
+       OO.ui.LabeledElement.call( this, this.$( '<span>' ), config );
+       OO.ui.TitledElement.call( this, this.$element, config );
+       OO.ui.ClippableElement.call( this, this.$group );
+
+       // Properties
+       this.active = false;
+       this.dragging = false;
+       this.onBlurHandler = OO.ui.bind( this.onBlur, this );
+       this.$handle = this.$( '<span>' );
+
+       // Events
+       this.$handle.on( {
+               'mousedown': OO.ui.bind( this.onHandleMouseDown, this ),
+               'mouseup': OO.ui.bind( this.onHandleMouseUp, this )
+       } );
+
+       // Initialization
+       this.$handle
+               .addClass( 'oo-ui-popupToolGroup-handle' )
+               .append( this.$icon, this.$label, this.$indicator );
+       this.$element
+               .addClass( 'oo-ui-popupToolGroup' )
+               .prepend( this.$handle );
+};
+
+/* Inheritance */
+
+OO.inheritClass( OO.ui.PopupToolGroup, OO.ui.ToolGroup );
+
+OO.mixinClass( OO.ui.PopupToolGroup, OO.ui.IconedElement );
+OO.mixinClass( OO.ui.PopupToolGroup, OO.ui.IndicatedElement );
+OO.mixinClass( OO.ui.PopupToolGroup, OO.ui.LabeledElement );
+OO.mixinClass( OO.ui.PopupToolGroup, OO.ui.TitledElement );
+OO.mixinClass( OO.ui.PopupToolGroup, OO.ui.ClippableElement );
+
+/* Static Properties */
+
+/* Methods */
+
+/**
+ * Handle focus being lost.
+ *
+ * The event is actually generated from a mouseup, so it is not a normal blur event object.
+ *
+ * @method
+ * @param {jQuery.Event} e Mouse up event
+ */
+OO.ui.PopupToolGroup.prototype.onBlur = function ( e ) {
+       // Only deactivate when clicking outside the dropdown element
+       if ( this.$( e.target ).closest( '.oo-ui-popupToolGroup' )[0] !== this.$element[0] ) {
+               this.setActive( false );
+       }
+};
+
+/**
+ * @inheritdoc
+ */
+OO.ui.PopupToolGroup.prototype.onMouseUp = function ( e ) {
+       this.setActive( false );
+       return OO.ui.ToolGroup.prototype.onMouseUp.call( this, e );
+};
+
+/**
+ * @inheritdoc
+ */
+OO.ui.PopupToolGroup.prototype.onMouseDown = function ( e ) {
+       return OO.ui.ToolGroup.prototype.onMouseDown.call( this, e );
+};
+
+/**
+ * Handle mouse up events.
+ *
+ * @method
+ * @param {jQuery.Event} e Mouse up event
+ */
+OO.ui.PopupToolGroup.prototype.onHandleMouseUp = function () {
+       return false;
+};
+
+/**
+ * Handle mouse down events.
+ *
+ * @method
+ * @param {jQuery.Event} e Mouse down event
+ */
+OO.ui.PopupToolGroup.prototype.onHandleMouseDown = function ( e ) {
+       if ( !this.disabled && e.which === 1 ) {
+               this.setActive( !this.active );
+       }
+       return false;
+};
+
+/**
+ * Switch into active mode.
+ *
+ * When active, mouseup events anywhere in the document will trigger deactivation.
+ *
+ * @method
+ */
+OO.ui.PopupToolGroup.prototype.setActive = function ( value ) {
+       value = !!value;
+       if ( this.active !== value ) {
+               this.active = value;
+               if ( value ) {
+                       this.setClipping( true );
+                       this.$element.addClass( 'oo-ui-popupToolGroup-active' );
+                       this.getElementDocument().addEventListener( 'mouseup', this.onBlurHandler, true );
+               } else {
+                       this.setClipping( false );
+                       this.$element.removeClass( 'oo-ui-popupToolGroup-active' );
+                       this.getElementDocument().removeEventListener( 'mouseup', this.onBlurHandler, true );
+               }
+       }
+};
+/**
+ * Drop down list layout of tools as labeled icon buttons.
+ *
+ * @class
+ * @abstract
+ * @extends OO.ui.PopupToolGroup
+ *
+ * @constructor
+ * @param {OO.ui.Toolbar} toolbar
+ * @param {Object} [config] Configuration options
+ */
+OO.ui.ListToolGroup = function OoUiListToolGroup( toolbar, config ) {
+       // Parent constructor
+       OO.ui.PopupToolGroup.call( this, toolbar, config );
+
+       // Initialization
+       this.$element.addClass( 'oo-ui-listToolGroup' );
+};
+
+/* Inheritance */
+
+OO.inheritClass( OO.ui.ListToolGroup, OO.ui.PopupToolGroup );
+
+/* Static Properties */
+
+OO.ui.ListToolGroup.static.accelTooltips = true;
+/**
+ * Drop down menu layout of tools as selectable menu items.
+ *
+ * @class
+ * @abstract
+ * @extends OO.ui.PopupToolGroup
+ *
+ * @constructor
+ * @param {OO.ui.Toolbar} toolbar
+ * @param {Object} [config] Configuration options
+ */
+OO.ui.MenuToolGroup = function OoUiMenuToolGroup( toolbar, config ) {
+       // Configuration initialization
+       config = config || {};
+
+       // Parent constructor
+       OO.ui.PopupToolGroup.call( this, toolbar, config );
+
+       // Events
+       this.toolbar.connect( this, { 'updateState': 'onUpdateState' } );
+
+       // Initialization
+       this.$element.addClass( 'oo-ui-menuToolGroup' );
+};
+
+/* Inheritance */
+
+OO.inheritClass( OO.ui.MenuToolGroup, OO.ui.PopupToolGroup );
+
+/* Static Properties */
+
+OO.ui.MenuToolGroup.static.accelTooltips = true;
+
+/* Methods */
+
+/**
+ * Handle the toolbar state being updated.
+ *
+ * When the state changes, the title of each active item in the menu will be joined together and
+ * used as a label for the group. The label will be empty if none of the items are active.
+ *
+ * @method
+ */
+OO.ui.MenuToolGroup.prototype.onUpdateState = function () {
+       var name,
+               labelTexts = [];
+
+       for ( name in this.tools ) {
+               if ( this.tools[name].isActive() ) {
+                       labelTexts.push( this.tools[name].getTitle() );
+               }
+       }
+
+       this.setLabel( labelTexts.join( ', ' ) );
+};
+/**
+ * UserInterface popup tool.
+ *
+ * @abstract
+ * @class
+ * @extends OO.ui.Tool
+ * @mixins OO.ui.PopuppableElement
+ *
+ * @constructor
+ * @param {OO.ui.Toolbar} toolbar
+ * @param {Object} [config] Configuration options
+ */
+OO.ui.PopupTool = function OoUiPopupTool( toolbar, config ) {
+       // Parent constructor
+       OO.ui.Tool.call( this, toolbar, config );
+
+       // Mixin constructors
+       OO.ui.PopuppableElement.call( this, config );
+
+       // Initialization
+       this.$element
+               .addClass( 'oo-ui-popupTool' )
+               .append( this.popup.$element );
+};
+
+/* Inheritance */
+
+OO.inheritClass( OO.ui.PopupTool, OO.ui.Tool );
+
+OO.mixinClass( OO.ui.PopupTool, OO.ui.PopuppableElement );
+
+/* Methods */
+
+/**
+ * Handle the tool being selected.
+ *
+ * @inheritdoc
+ */
+OO.ui.PopupTool.prototype.onSelect = function () {
+       if ( !this.disabled ) {
+               if ( this.popup.isVisible() ) {
+                       this.hidePopup();
+               } else {
+                       this.showPopup();
+               }
+       }
+       this.setActive( false );
+       return false;
+};
+
+/**
+ * Handle the toolbar state being updated.
+ *
+ * @inheritdoc
+ */
+OO.ui.PopupTool.prototype.onUpdateState = function () {
+       this.setActive( false );
+};
+/**
+ * Group widget.
+ *
+ * Use together with OO.ui.ItemWidget to make disabled state inheritable.
+ *
+ * @class
+ * @abstract
+ * @extends OO.ui.GroupElement
+ *
+ * @constructor
+ * @param {jQuery} $group Container node, assigned to #$group
+ * @param {Object} [config] Configuration options
+ */
+OO.ui.GroupWidget = function OoUiGroupWidget( $element, config ) {
+       // Parent constructor
+       OO.ui.GroupElement.call( this, $element, config );
+};
+
+/* Inheritance */
+
+OO.inheritClass( OO.ui.GroupWidget, OO.ui.GroupElement );
+
+/* Methods */
+
+/**
+ * Set the disabled state of the widget.
+ *
+ * This will also update the disabled state of child widgets.
+ *
+ * @method
+ * @param {boolean} disabled Disable widget
+ * @chainable
+ */
+OO.ui.GroupWidget.prototype.setDisabled = function ( disabled ) {
+       var i, len;
+
+       // Parent method
+       OO.ui.Widget.prototype.setDisabled.call( this, disabled );
+
+       // During construction, #setDisabled is called before the OO.ui.GroupElement constructor
+       if ( this.items ) {
+               for ( i = 0, len = this.items.length; i < len; i++ ) {
+                       this.items[i].updateDisabled();
+               }
+       }
+
+       return this;
+};
+/**
+ * Item widget.
+ *
+ * Use together with OO.ui.GroupWidget to make disabled state inheritable.
+ *
+ * @class
+ * @abstract
+ *
+ * @constructor
+ */
+OO.ui.ItemWidget = function OoUiItemWidget() {
+       //
+};
+
+/* Methods */
+
+/**
+ * Check if widget is disabled.
+ *
+ * Checks parent if present, making disabled state inheritable.
+ *
+ * @returns {boolean} Widget is disabled
+ */
+OO.ui.ItemWidget.prototype.isDisabled = function () {
+       return this.disabled ||
+               ( this.elementGroup instanceof OO.ui.Widget && this.elementGroup.isDisabled() );
+};
+
+/**
+ * Set group element is in.
+ *
+ * @param {OO.ui.GroupElement|null} group Group element, null if none
+ * @chainable
+ */
+OO.ui.ItemWidget.prototype.setElementGroup = function ( group ) {
+       // Parent method
+       OO.ui.Element.prototype.setElementGroup.call( this, group );
+
+       // Initialize item disabled states
+       this.updateDisabled();
+
+       return this;
+};
+/**
+ * Container for multiple related buttons.
+ *
+ * @class
+ * @extends OO.ui.Widget
+ * @mixin OO.ui.GroupElement
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ */
+OO.ui.ButtonGroupWidget = function OoUiButtonGroupWidget( config ) {
+       // Parent constructor
+       OO.ui.Widget.call( this, config );
+
+       // Mixin constructors
+       OO.ui.GroupElement.call( this, this.$element, config );
+
+       // Initialization
+       this.$element.addClass( 'oo-ui-buttonGroupWidget' );
+};
+
+/* Inheritance */
+
+OO.inheritClass( OO.ui.ButtonGroupWidget, OO.ui.Widget );
+
+OO.mixinClass( OO.ui.ButtonGroupWidget, OO.ui.GroupElement );
+/**
+ * Creates an OO.ui.ButtonWidget object.
+ *
+ * @class
+ * @abstract
+ * @extends OO.ui.Widget
+ * @mixins OO.ui.ButtonedElement
+ * @mixins OO.ui.IconedElement
+ * @mixins OO.ui.IndicatedElement
+ * @mixins OO.ui.LabeledElement
+ * @mixins OO.ui.TitledElement
+ * @mixins OO.ui.FlaggableElement
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ * @cfg {string} [title=''] Title text
+ * @cfg {string} [href] Hyperlink to visit when clicked
+ * @cfg {string} [target] Target to open hyperlink in
+ */
+OO.ui.ButtonWidget = function OoUiButtonWidget( config ) {
+       // Configuration initialization
+       config = $.extend( { 'target': '_blank' }, config );
+
+       // Parent constructor
+       OO.ui.Widget.call( this, config );
+
+       // Mixin constructors
+       OO.ui.ButtonedElement.call( this, this.$( '<a>' ), config );
+       OO.ui.IconedElement.call( this, this.$( '<span>' ), config );
+       OO.ui.IndicatedElement.call( this, this.$( '<span>' ), config );
+       OO.ui.LabeledElement.call( this, this.$( '<span>' ), config );
+       OO.ui.TitledElement.call( this, this.$button, config );
+       OO.ui.FlaggableElement.call( this, config );
+
+       // Properties
+       this.isHyperlink = typeof config.href === 'string';
+
+       // Events
+       this.$button.on( {
+               'click': OO.ui.bind( this.onClick, this ),
+               'keypress': OO.ui.bind( this.onKeyPress, this )
+       } );
+
+       // Initialization
+       this.$button
+               .append( this.$icon, this.$label, this.$indicator )
+               .attr( { 'href': config.href, 'target': config.target } );
+       this.$element
+               .addClass( 'oo-ui-buttonWidget' )
+               .append( this.$button );
+};
+
+/* Inheritance */
+
+OO.inheritClass( OO.ui.ButtonWidget, OO.ui.Widget );
+
+OO.mixinClass( OO.ui.ButtonWidget, OO.ui.ButtonedElement );
+OO.mixinClass( OO.ui.ButtonWidget, OO.ui.IconedElement );
+OO.mixinClass( OO.ui.ButtonWidget, OO.ui.IndicatedElement );
+OO.mixinClass( OO.ui.ButtonWidget, OO.ui.LabeledElement );
+OO.mixinClass( OO.ui.ButtonWidget, OO.ui.TitledElement );
+OO.mixinClass( OO.ui.ButtonWidget, OO.ui.FlaggableElement );
+
+/* Events */
+
+/**
+ * @event click
+ */
+
+/* Methods */
+
+/**
+ * Handles mouse click events.
+ *
+ * @method
+ * @param {jQuery.Event} e Mouse click event
+ * @fires click
+ */
+OO.ui.ButtonWidget.prototype.onClick = function () {
+       if ( !this.disabled ) {
+               this.emit( 'click' );
+               if ( this.isHyperlink ) {
+                       return true;
+               }
+       }
+       return false;
+};
+
+/**
+ * Handles keypress events.
+ *
+ * @method
+ * @param {jQuery.Event} e Keypress event
+ * @fires click
+ */
+OO.ui.ButtonWidget.prototype.onKeyPress = function ( e ) {
+       if ( !this.disabled && e.which === OO.ui.Keys.SPACE ) {
+               if ( this.isHyperlink ) {
+                       this.onClick();
+                       return true;
+               }
+       }
+       return false;
+};
+/**
+ * Creates an OO.ui.InputWidget object.
+ *
+ * @class
+ * @abstract
+ * @extends OO.ui.Widget
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ * @cfg {string} [name=''] HTML input name
+ * @cfg {string} [value=''] Input value
+ * @cfg {boolean} [readOnly=false] Prevent changes
+ * @cfg {Function} [inputFilter] Filter function to apply to the input. Takes a string argument and returns a string.
+ */
+OO.ui.InputWidget = function OoUiInputWidget( config ) {
+       // Config intialization
+       config = $.extend( { 'readOnly': false }, config );
+
+       // Parent constructor
+       OO.ui.Widget.call( this, config );
+
+       // Properties
+       this.$input = this.getInputElement( config );
+       this.value = '';
+       this.readOnly = false;
+       this.inputFilter = config.inputFilter;
+
+       // Events
+       this.$input.on( 'keydown mouseup cut paste change input select', OO.ui.bind( this.onEdit, this ) );
+
+       // Initialization
+       this.$input
+               .attr( 'name', config.name )
+               .prop( 'disabled', this.disabled );
+       this.setReadOnly( config.readOnly );
+       this.$element.addClass( 'oo-ui-inputWidget' ).append( this.$input );
+       this.setValue( config.value );
+};
+
+/* Inheritance */
+
+OO.inheritClass( OO.ui.InputWidget, OO.ui.Widget );
+
+/* Events */
+
+/**
+ * @event change
+ * @param value
+ */
+
+/* Methods */
+
+/**
+ * Get input element.
+ *
+ * @method
+ * @param {Object} [config] Configuration options
+ * @returns {jQuery} Input element
+ */
+OO.ui.InputWidget.prototype.getInputElement = function () {
+       return this.$( '<input>' );
+};
+
+/**
+ * Handle potentially value-changing events.
+ *
+ * @method
+ * @param {jQuery.Event} e Key down, mouse up, cut, paste, change, input, or select event
+ */
+OO.ui.InputWidget.prototype.onEdit = function () {
+       if ( !this.disabled ) {
+               // Allow the stack to clear so the value will be updated
+               setTimeout( OO.ui.bind( function () {
+                       this.setValue( this.$input.val() );
+               }, this ) );
+       }
+};
+
+/**
+ * Get the value of the input.
+ *
+ * @method
+ * @returns {string} Input value
+ */
+OO.ui.InputWidget.prototype.getValue = function () {
+       return this.value;
+};
+
+/**
+ * Sets the direction of the current input, either RTL or LTR
+ *
+ * @method
+ * @param {boolean} isRTL
+ */
+OO.ui.InputWidget.prototype.setRTL = function ( isRTL ) {
+       if ( isRTL ) {
+               this.$input.removeClass( 'oo-ui-ltr' );
+               this.$input.addClass( 'oo-ui-rtl' );
+       } else {
+               this.$input.removeClass( 'oo-ui-rtl' );
+               this.$input.addClass( 'oo-ui-ltr' );
+       }
+};
+
+/**
+ * Set the value of the input.
+ *
+ * @method
+ * @param {string} value New value
+ * @fires change
+ * @chainable
+ */
+OO.ui.InputWidget.prototype.setValue = function ( value ) {
+       value = this.sanitizeValue( value );
+       if ( this.value !== value ) {
+               this.value = value;
+               this.emit( 'change', this.value );
+       }
+       // Update the DOM if it has changed. Note that with sanitizeValue, it
+       // is possible for the DOM value to change without this.value changing.
+       if ( this.$input.val() !== this.value ) {
+               this.$input.val( this.value );
+       }
+       return this;
+};
+
+/**
+ * Sanitize incoming value.
+ *
+ * Ensures value is a string, and converts undefined and null to empty strings.
+ *
+ * @method
+ * @param {string} value Original value
+ * @returns {string} Sanitized value
+ */
+OO.ui.InputWidget.prototype.sanitizeValue = function ( value ) {
+       if ( value === undefined || value === null ) {
+               return '';
+       } else if ( this.inputFilter ) {
+               return this.inputFilter( String( value ) );
+       } else {
+               return String( value );
+       }
+};
+
+/**
+ * Check if the widget is read-only.
+ *
+ * @method
+ * @param {boolean} Input is read-only
+ */
+OO.ui.InputWidget.prototype.isReadOnly = function () {
+       return this.readOnly;
+};
+
+/**
+ * Set the read-only state of the widget.
+ *
+ * This should probably change the widgets's appearance and prevent it from being used.
+ *
+ * @method
+ * @param {boolean} state Make input read-only
+ * @chainable
+ */
+OO.ui.InputWidget.prototype.setReadOnly = function ( state ) {
+       this.readOnly = !!state;
+       this.$input.prop( 'readonly', this.readOnly );
+       return this;
+};
+
+/**
+ * @inheritdoc
+ */
+OO.ui.InputWidget.prototype.setDisabled = function ( state ) {
+       OO.ui.Widget.prototype.setDisabled.call( this, state );
+       if ( this.$input ) {
+               this.$input.prop( 'disabled', this.disabled );
+       }
+       return this;
+};/**
+ * Creates an OO.ui.CheckboxInputWidget object.
+ *
+ * @class
+ * @extends OO.ui.InputWidget
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ */
+OO.ui.CheckboxInputWidget = function OoUiCheckboxInputWidget( config ) {
+       // Parent constructor
+       OO.ui.InputWidget.call( this, config );
+
+       // Initialization
+       this.$element.addClass( 'oo-ui-checkboxInputWidget' );
+};
+
+/* Inheritance */
+
+OO.inheritClass( OO.ui.CheckboxInputWidget, OO.ui.InputWidget );
+
+/* Events */
+
+/* Methods */
+
+/**
+ * Get input element.
+ *
+ * @returns {jQuery} Input element
+ */
+OO.ui.CheckboxInputWidget.prototype.getInputElement = function () {
+       return this.$( '<input type="checkbox" />' );
+};
+
+/**
+ * Get checked state of the checkbox
+ *
+ * @returns {boolean} If the checkbox is checked
+ */
+OO.ui.CheckboxInputWidget.prototype.getValue = function () {
+       return this.value;
+};
+
+/**
+ * Set value
+ */
+OO.ui.CheckboxInputWidget.prototype.setValue = function ( value ) {
+       value = !!value;
+       if ( this.value !== value ) {
+               this.value = value;
+               this.$input.prop( 'checked', this.value );
+               this.emit( 'change', this.value );
+       }
+};
+
+/**
+ * @inheritdoc
+ */
+OO.ui.CheckboxInputWidget.prototype.onEdit = function () {
+       if ( !this.disabled ) {
+               // Allow the stack to clear so the value will be updated
+               setTimeout( OO.ui.bind( function () {
+                       this.setValue( this.$input.prop( 'checked' ) );
+               }, this ) );
+       }
+};
+/**
+ * Creates an OO.ui.CheckboxWidget object.
+ *
+ * @class
+ * @extends OO.ui.CheckboxInputWidget
+ * @mixins OO.ui.LabeledElement
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ * @cfg {string} [label=''] Label
+ */
+OO.ui.CheckboxWidget = function OoUiCheckboxWidget( config ) {
+       // Configuration initialization
+       config = config || {};
+
+       // Parent constructor
+       OO.ui.CheckboxInputWidget.call( this, config );
+
+       // Mixin constructors
+       OO.ui.LabeledElement.call( this, this.$( '<span>' ) , config );
+
+       // Initialization
+       this.$element
+               .addClass( 'oo-ui-checkboxWidget' )
+               .append( this.$( '<label>' ).append( this.$input, this.$label ) );
+};
+
+/* Inheritance */
+
+OO.inheritClass( OO.ui.CheckboxWidget, OO.ui.CheckboxInputWidget );
+
+OO.mixinClass( OO.ui.CheckboxWidget, OO.ui.LabeledElement );
+/**
+ * Creates an OO.ui.InputLabelWidget object.
+ *
+ * CSS classes will be added to the button for each flag, each prefixed with 'oo-ui-InputLabelWidget-'
+ *
+ * @class
+ * @extends OO.ui.Widget
+ * @mixins OO.ui.LabeledElement
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ * @cfg {OO.ui.InputWidget|null} [input] Related input widget
+ */
+OO.ui.InputLabelWidget = function OoUiInputLabelWidget( config ) {
+       // Config intialization
+       config = $.extend( { 'input': null }, config );
+
+       // Parent constructor
+       OO.ui.Widget.call( this, config );
+
+       // Mixin constructors
+       OO.ui.LabeledElement.call( this, this.$element, config );
+
+       // Properties
+       this.input = config.input;
+
+       // Events
+       this.$element.on( 'click', OO.ui.bind( this.onClick, this ) );
+
+       // Initialization
+       this.$element.addClass( 'oo-ui-inputLabelWidget' );
+};
+
+/* Inheritance */
+
+OO.inheritClass( OO.ui.InputLabelWidget, OO.ui.Widget );
+
+OO.mixinClass( OO.ui.InputLabelWidget, OO.ui.LabeledElement );
+
+/* Static Properties */
+
+OO.ui.InputLabelWidget.static.tagName = 'label';
+
+/* Methods */
+
+/**
+ * Handles mouse click events.
+ *
+ * @method
+ * @param {jQuery.Event} e Mouse click event
+ */
+OO.ui.InputLabelWidget.prototype.onClick = function () {
+       if ( !this.disabled && this.input ) {
+               this.input.$input.focus();
+       }
+       return false;
+};
+/**
+ * Lookup input widget.
+ *
+ * Mixin that adds a menu showing suggested values to a text input. Subclasses must handle `select`
+ * events on #lookupMenu to make use of selections.
+ *
+ * @class
+ * @abstract
+ *
+ * @constructor
+ * @param {OO.ui.TextInputWidget} input Input widget
+ * @param {Object} [config] Configuration options
+ * @cfg {jQuery} [$overlay=this.$( 'body' )] Overlay layer
+ */
+OO.ui.LookupInputWidget = function OoUiLookupInputWidget( input, config ) {
+       // Config intialization
+       config = config || {};
+
+       // Properties
+       this.lookupInput = input;
+       this.$overlay = config.$overlay || this.$( 'body,.oo-ui-window-overlay' ).last();
+       this.lookupMenu = new OO.ui.TextInputMenuWidget( this, {
+               '$': OO.ui.Element.getJQuery( this.$overlay ),
+               'input': this.lookupInput,
+               '$container': config.$container
+       } );
+       this.lookupCache = {};
+       this.lookupQuery = null;
+       this.lookupRequest = null;
+       this.populating = false;
+
+       // Events
+       this.$overlay.append( this.lookupMenu.$element );
+
+       this.lookupInput.$input.on( {
+               'focus': OO.ui.bind( this.onLookupInputFocus, this ),
+               'blur': OO.ui.bind( this.onLookupInputBlur, this ),
+               'mousedown': OO.ui.bind( this.onLookupInputMouseDown, this )
+       } );
+       this.lookupInput.connect( this, { 'change': 'onLookupInputChange' } );
+
+       // Initialization
+       this.$element.addClass( 'oo-ui-lookupWidget' );
+       this.lookupMenu.$element.addClass( 'oo-ui-lookupWidget-menu' );
+};
+
+/* Methods */
+
+/**
+ * Handle input focus event.
+ *
+ * @method
+ * @param {jQuery.Event} e Input focus event
+ */
+OO.ui.LookupInputWidget.prototype.onLookupInputFocus = function () {
+       this.openLookupMenu();
+};
+
+/**
+ * Handle input blur event.
+ *
+ * @method
+ * @param {jQuery.Event} e Input blur event
+ */
+OO.ui.LookupInputWidget.prototype.onLookupInputBlur = function () {
+       this.lookupMenu.hide();
+};
+
+/**
+ * Handle input mouse down event.
+ *
+ * @method
+ * @param {jQuery.Event} e Input mouse down event
+ */
+OO.ui.LookupInputWidget.prototype.onLookupInputMouseDown = function () {
+       this.openLookupMenu();
+};
+
+/**
+ * Handle input change event.
+ *
+ * @method
+ * @param {string} value New input value
+ */
+OO.ui.LookupInputWidget.prototype.onLookupInputChange = function () {
+       this.openLookupMenu();
+};
+
+/**
+ * Open the menu.
+ *
+ * @method
+ * @chainable
+ */
+OO.ui.LookupInputWidget.prototype.openLookupMenu = function () {
+       var value = this.lookupInput.getValue();
+
+       if ( this.lookupMenu.$input.is( ':focus' ) && $.trim( value ) !== '' ) {
+               this.populateLookupMenu();
+               if ( !this.lookupMenu.isVisible() ) {
+                       this.lookupMenu.show();
+               }
+       } else {
+               this.lookupMenu.clearItems();
+               this.lookupMenu.hide();
+       }
+
+       return this;
+};
+
+/**
+ * Populate lookup menu with current information.
+ *
+ * @method
+ * @chainable
+ */
+OO.ui.LookupInputWidget.prototype.populateLookupMenu = function () {
+       if ( !this.populating ) {
+               this.populating = true;
+               this.getLookupMenuItems()
+                       .done( OO.ui.bind( function ( items ) {
+                               this.lookupMenu.clearItems();
+                               if ( items.length ) {
+                                       this.lookupMenu.show();
+                                       this.lookupMenu.addItems( items );
+                                       this.initializeLookupMenuSelection();
+                                       this.openLookupMenu();
+                               } else {
+                                       this.lookupMenu.hide();
+                               }
+                               this.populating = false;
+                       }, this ) )
+                       .fail( OO.ui.bind( function () {
+                               this.lookupMenu.clearItems();
+                               this.populating = false;
+                       }, this ) );
+       }
+
+       return this;
+};
+
+/**
+ * Set selection in the lookup menu with current information.
+ *
+ * @method
+ * @chainable
+ */
+OO.ui.LookupInputWidget.prototype.initializeLookupMenuSelection = function () {
+       if ( !this.lookupMenu.getSelectedItem() ) {
+               this.lookupMenu.intializeSelection( this.lookupMenu.getFirstSelectableItem() );
+       }
+       this.lookupMenu.highlightItem( this.lookupMenu.getSelectedItem() );
+};
+
+/**
+ * Get lookup menu items for the current query.
+ *
+ * @method
+ * @returns {jQuery.Promise} Promise object which will be passed menu items as the first argument
+ * of the done event
+ */
+OO.ui.LookupInputWidget.prototype.getLookupMenuItems = function () {
+       var value = this.lookupInput.getValue(),
+               deferred = $.Deferred();
+
+       if ( value && value !== this.lookupQuery ) {
+               // Abort current request if query has changed
+               if ( this.lookupRequest ) {
+                       this.lookupRequest.abort();
+                       this.lookupQuery = null;
+                       this.lookupRequest = null;
+               }
+               if ( value in this.lookupCache ) {
+                       deferred.resolve( this.getLookupMenuItemsFromData( this.lookupCache[value] ) );
+               } else {
+                       this.lookupQuery = value;
+                       this.lookupRequest = this.getLookupRequest()
+                               .always( OO.ui.bind( function () {
+                                       this.lookupQuery = null;
+                                       this.lookupRequest = null;
+                               }, this ) )
+                               .done( OO.ui.bind( function ( data ) {
+                                       this.lookupCache[value] = this.getLookupCacheItemFromData( data );
+                                       deferred.resolve( this.getLookupMenuItemsFromData( this.lookupCache[value] ) );
+                               }, this ) )
+                               .fail( function () {
+                                       deferred.reject();
+                               } );
+                       this.pushPending();
+                       this.lookupRequest.always( OO.ui.bind( function () {
+                               this.popPending();
+                       }, this ) );
+               }
+       }
+       return deferred.promise();
+};
+
+/**
+ * Get a new request object of the current lookup query value.
+ *
+ * @method
+ * @abstract
+ * @returns {jqXHR} jQuery AJAX object, or promise object with an .abort() method
+ */
+OO.ui.LookupInputWidget.prototype.getLookupRequest = function () {
+       // Stub, implemented in subclass
+       return null;
+};
+
+/**
+ * Handle successful lookup request.
+ *
+ * Overriding methods should call #populateLookupMenu when results are available and cache results
+ * for future lookups in #lookupCache as an array of #OO.ui.MenuItemWidget objects.
+ *
+ * @method
+ * @abstract
+ * @param {Mixed} data Response from server
+ */
+OO.ui.LookupInputWidget.prototype.onLookupRequestDone = function () {
+       // Stub, implemented in subclass
+};
+
+/**
+ * Get a list of menu item widgets from the data stored by the lookup request's done handler.
+ *
+ * @method
+ * @abstract
+ * @param {Mixed} data Cached result data, usually an array
+ * @returns {OO.ui.MenuItemWidget[]} Menu items
+ */
+OO.ui.LookupInputWidget.prototype.getLookupMenuItemsFromData = function () {
+       // Stub, implemented in subclass
+       return [];
+};
+/**
+ * Creates an OO.ui.OptionWidget object.
+ *
+ * @class
+ * @abstract
+ * @extends OO.ui.Widget
+ * @mixins OO.ui.IconedElement
+ * @mixins OO.ui.LabeledElement
+ * @mixins OO.ui.IndicatedElement
+ *
+ * @constructor
+ * @param {Mixed} data Option data
+ * @param {Object} [config] Configuration options
+ * @cfg {boolean} [selected=false] Select option
+ * @cfg {boolean} [highlighted=false] Highlight option
+ * @cfg {string} [rel] Value for `rel` attribute in DOM, allowing per-option styling
+ */
+OO.ui.OptionWidget = function OoUiOptionWidget( data, config ) {
+       // Config intialization
+       config = config || {};
+
+       // Parent constructor
+       OO.ui.Widget.call( this, config );
+
+       // Mixin constructors
+       OO.ui.ItemWidget.call( this );
+       OO.ui.IconedElement.call( this, this.$( '<span>' ), config );
+       OO.ui.LabeledElement.call( this, this.$( '<span>' ), config );
+       OO.ui.IndicatedElement.call( this, this.$( '<span>' ), config );
+
+       // Properties
+       this.data = data;
+       this.selected = false;
+       this.highlighted = false;
+
+       // Initialization
+       this.$element
+               .data( 'oo-ui-optionWidget', this )
+               .attr( 'rel', config.rel )
+               .addClass( 'oo-ui-optionWidget' )
+               .append( this.$label );
+       this.setSelected( config.selected );
+       this.setHighlighted( config.highlighted );
+
+       // Options
+       this.$element
+               .prepend( this.$icon )
+               .append( this.$indicator );
+};
+
+/* Inheritance */
+
+OO.inheritClass( OO.ui.OptionWidget, OO.ui.Widget );
+
+OO.mixinClass( OO.ui.OptionWidget, OO.ui.ItemWidget );
+OO.mixinClass( OO.ui.OptionWidget, OO.ui.IconedElement );
+OO.mixinClass( OO.ui.OptionWidget, OO.ui.LabeledElement );
+OO.mixinClass( OO.ui.OptionWidget, OO.ui.IndicatedElement );
+
+/* Static Properties */
+
+OO.ui.OptionWidget.static.tagName = 'li';
+
+OO.ui.OptionWidget.static.selectable = true;
+
+OO.ui.OptionWidget.static.highlightable = true;
+
+OO.ui.OptionWidget.static.scrollIntoViewOnSelect = false;
+
+/* Methods */
+
+/**
+ * Check if option can be selected.
+ *
+ * @method
+ * @returns {boolean} Item is selectable
+ */
+OO.ui.OptionWidget.prototype.isSelectable = function () {
+       return this.constructor.static.selectable && !this.disabled;
+};
+
+/**
+ * Check if option can be highlighted.
+ *
+ * @method
+ * @returns {boolean} Item is highlightable
+ */
+OO.ui.OptionWidget.prototype.isHighlightable = function () {
+       return this.constructor.static.highlightable && !this.disabled;
+};
+
+/**
+ * Check if option is selected.
+ *
+ * @method
+ * @returns {boolean} Item is selected
+ */
+OO.ui.OptionWidget.prototype.isSelected = function () {
+       return this.selected;
+};
+
+/**
+ * Check if option is highlighted.
+ *
+ * @method
+ * @returns {boolean} Item is highlighted
+ */
+OO.ui.OptionWidget.prototype.isHighlighted = function () {
+       return this.highlighted;
+};
+
+/**
+ * Set selected state.
+ *
+ * @method
+ * @param {boolean} [state=false] Select option
+ * @chainable
+ */
+OO.ui.OptionWidget.prototype.setSelected = function ( state ) {
+       if ( !this.disabled && this.constructor.static.selectable ) {
+               this.selected = !!state;
+               if ( this.selected ) {
+                       this.$element.addClass( 'oo-ui-optionWidget-selected' );
+                       if ( this.constructor.static.scrollIntoViewOnSelect ) {
+                               this.scrollElementIntoView();
+                       }
+               } else {
+                       this.$element.removeClass( 'oo-ui-optionWidget-selected' );
+               }
+       }
+       return this;
+};
+
+/**
+ * Set highlighted state.
+ *
+ * @method
+ * @param {boolean} [state=false] Highlight option
+ * @chainable
+ */
+OO.ui.OptionWidget.prototype.setHighlighted = function ( state ) {
+       if ( !this.disabled && this.constructor.static.highlightable ) {
+               this.highlighted = !!state;
+               if ( this.highlighted ) {
+                       this.$element.addClass( 'oo-ui-optionWidget-highlighted' );
+               } else {
+                       this.$element.removeClass( 'oo-ui-optionWidget-highlighted' );
+               }
+       }
+       return this;
+};
+
+/**
+ * Make the option's highlight flash.
+ *
+ * @method
+ * @param {Function} [done] Callback to execute when flash effect is complete.
+ */
+OO.ui.OptionWidget.prototype.flash = function ( done ) {
+       var $this = this.$element;
+
+       if ( !this.disabled && this.constructor.static.highlightable ) {
+               $this.removeClass( 'oo-ui-optionWidget-highlighted' );
+               setTimeout( OO.ui.bind( function () {
+                       $this.addClass( 'oo-ui-optionWidget-highlighted' );
+                       if ( done ) {
+                               setTimeout( done, 100 );
+                       }
+               }, this ), 100 );
+       }
+};
+
+/**
+ * Get option data.
+ *
+ * @method
+ * @returns {Mixed} Option data
+ */
+OO.ui.OptionWidget.prototype.getData = function () {
+       return this.data;
+};
+/**
+ * Create an OO.ui.SelectWidget object.
+ *
+ * @class
+ * @abstract
+ * @extends OO.ui.Widget
+ * @mixin OO.ui.GroupElement
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ */
+OO.ui.SelectWidget = function OoUiSelectWidget( config ) {
+       // Config intialization
+       config = config || {};
+
+       // Parent constructor
+       OO.ui.Widget.call( this, config );
+
+       // Mixin constructors
+       OO.ui.GroupWidget.call( this, this.$element, config );
+
+       // Properties
+       this.pressed = false;
+       this.selecting = null;
+       this.hashes = {};
+
+       // Events
+       this.$element.on( {
+               'mousedown': OO.ui.bind( this.onMouseDown, this ),
+               'mouseup': OO.ui.bind( this.onMouseUp, this ),
+               'mousemove': OO.ui.bind( this.onMouseMove, this ),
+               'mouseover': OO.ui.bind( this.onMouseOver, this ),
+               'mouseleave': OO.ui.bind( this.onMouseLeave, this )
+       } );
+
+       // Initialization
+       this.$element.addClass( 'oo-ui-selectWidget' );
+};
+
+/* Inheritance */
+
+OO.inheritClass( OO.ui.SelectWidget, OO.ui.Widget );
+
+// Need to mixin base class as well
+OO.mixinClass( OO.ui.SelectWidget, OO.ui.GroupElement );
+
+OO.mixinClass( OO.ui.SelectWidget, OO.ui.GroupWidget );
+
+/* Events */
+
+/**
+ * @event highlight
+ * @param {OO.ui.OptionWidget|null} item Highlighted item
+ */
+
+/**
+ * @event select
+ * @param {OO.ui.OptionWidget|null} item Selected item
+ */
+
+/**
+ * @event add
+ * @param {OO.ui.OptionWidget[]} items Added items
+ * @param {number} index Index items were added at
+ */
+
+/**
+ * @event remove
+ * @param {OO.ui.OptionWidget[]} items Removed items
+ */
+
+/* Static Properties */
+
+OO.ui.SelectWidget.static.tagName = 'ul';
+
+/* Methods */
+
+/**
+ * Handle mouse down events.
+ *
+ * @method
+ * @private
+ * @param {jQuery.Event} e Mouse down event
+ */
+OO.ui.SelectWidget.prototype.onMouseDown = function ( e ) {
+       var item;
+
+       if ( !this.disabled && e.which === 1 ) {
+               this.pressed = true;
+               item = this.getTargetItem( e );
+               if ( item && item.isSelectable() ) {
+                       this.intializeSelection( item );
+                       this.selecting = item;
+                       this.$( this.$.context ).one( 'mouseup', OO.ui.bind( this.onMouseUp, this ) );
+               }
+       }
+       return false;
+};
+
+/**
+ * Handle mouse up events.
+ *
+ * @method
+ * @private
+ * @param {jQuery.Event} e Mouse up event
+ */
+OO.ui.SelectWidget.prototype.onMouseUp = function ( e ) {
+       var item;
+       this.pressed = false;
+       if ( !this.selecting ) {
+               item = this.getTargetItem( e );
+               if ( item && item.isSelectable() ) {
+                       this.selecting = item;
+               }
+       }
+       if ( !this.disabled && e.which === 1 && this.selecting ) {
+               this.selectItem( this.selecting );
+               this.selecting = null;
+       }
+       return false;
+};
+
+/**
+ * Handle mouse move events.
+ *
+ * @method
+ * @private
+ * @param {jQuery.Event} e Mouse move event
+ */
+OO.ui.SelectWidget.prototype.onMouseMove = function ( e ) {
+       var item;
+
+       if ( !this.disabled && this.pressed ) {
+               item = this.getTargetItem( e );
+               if ( item && item !== this.selecting && item.isSelectable() ) {
+                       this.intializeSelection( item );
+                       this.selecting = item;
+               }
+       }
+       return false;
+};
+
+/**
+ * Handle mouse over events.
+ *
+ * @method
+ * @private
+ * @param {jQuery.Event} e Mouse over event
+ */
+OO.ui.SelectWidget.prototype.onMouseOver = function ( e ) {
+       var item;
+
+       if ( !this.disabled ) {
+               item = this.getTargetItem( e );
+               if ( item && item.isHighlightable() ) {
+                       this.highlightItem( item );
+               }
+       }
+       return false;
+};
+
+/**
+ * Handle mouse leave events.
+ *
+ * @method
+ * @private
+ * @param {jQuery.Event} e Mouse over event
+ */
+OO.ui.SelectWidget.prototype.onMouseLeave = function () {
+       if ( !this.disabled ) {
+               this.highlightItem();
+       }
+       return false;
+};
+
+/**
+ * Get the closest item to a jQuery.Event.
+ *
+ * @method
+ * @private
+ * @param {jQuery.Event} e
+ * @returns {OO.ui.OptionWidget|null} Outline item widget, `null` if none was found
+ */
+OO.ui.SelectWidget.prototype.getTargetItem = function ( e ) {
+       var $item = this.$( e.target ).closest( '.oo-ui-optionWidget' );
+       if ( $item.length ) {
+               return $item.data( 'oo-ui-optionWidget' );
+       }
+       return null;
+};
+
+/**
+ * Get selected item.
+ *
+ * @method
+ * @returns {OO.ui.OptionWidget|null} Selected item, `null` if no item is selected
+ */
+OO.ui.SelectWidget.prototype.getSelectedItem = function () {
+       var i, len;
+
+       for ( i = 0, len = this.items.length; i < len; i++ ) {
+               if ( this.items[i].isSelected() ) {
+                       return this.items[i];
+               }
+       }
+       return null;
+};
+
+/**
+ * Get highlighted item.
+ *
+ * @method
+ * @returns {OO.ui.OptionWidget|null} Highlighted item, `null` if no item is highlighted
+ */
+OO.ui.SelectWidget.prototype.getHighlightedItem = function () {
+       var i, len;
+
+       for ( i = 0, len = this.items.length; i < len; i++ ) {
+               if ( this.items[i].isHighlighted() ) {
+                       return this.items[i];
+               }
+       }
+       return null;
+};
+
+/**
+ * Get an existing item with equivilant data.
+ *
+ * @method
+ * @param {Object} data Item data to search for
+ * @returns {OO.ui.OptionWidget|null} Item with equivilent value, `null` if none exists
+ */
+OO.ui.SelectWidget.prototype.getItemFromData = function ( data ) {
+       var hash = OO.getHash( data );
+
+       if ( hash in this.hashes ) {
+               return this.hashes[hash];
+       }
+
+       return null;
+};
+
+/**
+ * Highlight an item.
+ *
+ * Highlighting is mutually exclusive.
+ *
+ * @method
+ * @param {OO.ui.OptionWidget} [item] Item to highlight, omit to deselect all
+ * @fires highlight
+ * @chainable
+ */
+OO.ui.SelectWidget.prototype.highlightItem = function ( item ) {
+       var i, len;
+
+       for ( i = 0, len = this.items.length; i < len; i++ ) {
+               this.items[i].setHighlighted( this.items[i] === item );
+       }
+       this.emit( 'highlight', item );
+
+       return this;
+};
+
+/**
+ * Select an item.
+ *
+ * @method
+ * @param {OO.ui.OptionWidget} [item] Item to select, omit to deselect all
+ * @fires select
+ * @chainable
+ */
+OO.ui.SelectWidget.prototype.selectItem = function ( item ) {
+       var i, len;
+
+       for ( i = 0, len = this.items.length; i < len; i++ ) {
+               this.items[i].setSelected( this.items[i] === item );
+       }
+       this.emit( 'select', item );
+
+       return this;
+};
+
+/**
+ * Setup selection and highlighting.
+ *
+ * This should be used to synchronize the UI with the model without emitting events that would in
+ * turn update the model.
+ *
+ * @param {OO.ui.OptionWidget} [item] Item to select
+ * @chainable
+ */
+OO.ui.SelectWidget.prototype.intializeSelection = function( item ) {
+       var i, len, selected;
+
+       for ( i = 0, len = this.items.length; i < len; i++ ) {
+               selected = this.items[i] === item;
+               this.items[i].setSelected( selected );
+               this.items[i].setHighlighted( selected );
+       }
+
+       return this;
+};
+
+/**
+ * Get an item relative to another one.
+ *
+ * @method
+ * @param {OO.ui.OptionWidget} item Item to start at
+ * @param {number} direction Direction to move in
+ * @returns {OO.ui.OptionWidget|null} Item at position, `null` if there are no items in the menu
+ */
+OO.ui.SelectWidget.prototype.getRelativeSelectableItem = function ( item, direction ) {
+       var inc = direction > 0 ? 1 : -1,
+               len = this.items.length,
+               index = item instanceof OO.ui.OptionWidget ?
+                       this.items.indexOf( item ) : ( inc > 0 ? -1 : 0 ),
+               stopAt = Math.max( Math.min( index, len - 1 ), 0 ),
+               i = inc > 0 ?
+                       // Default to 0 instead of -1, if nothing is selected let's start at the beginning
+                       Math.max( index, -1 ) :
+                       // Default to n-1 instead of -1, if nothing is selected let's start at the end
+                       Math.min( index, len );
+
+       while ( true ) {
+               i = ( i + inc + len ) % len;
+               item = this.items[i];
+               if ( item instanceof OO.ui.OptionWidget && item.isSelectable() ) {
+                       return item;
+               }
+               // Stop iterating when we've looped all the way around
+               if ( i === stopAt ) {
+                       break;
+               }
+       }
+       return null;
+};
+
+/**
+ * Get the next selectable item.
+ *
+ * @method
+ * @returns {OO.ui.OptionWidget|null} Item, `null` if ther aren't any selectable items
+ */
+OO.ui.SelectWidget.prototype.getFirstSelectableItem = function () {
+       var i, len, item;
+
+       for ( i = 0, len = this.items.length; i < len; i++ ) {
+               item = this.items[i];
+               if ( item instanceof OO.ui.OptionWidget && item.isSelectable() ) {
+                       return item;
+               }
+       }
+
+       return null;
+};
+
+/**
+ * Add items.
+ *
+ * When items are added with the same values as existing items, the existing items will be
+ * automatically removed before the new items are added.
+ *
+ * @method
+ * @param {OO.ui.OptionWidget[]} items Items to add
+ * @param {number} [index] Index to insert items after
+ * @fires add
+ * @chainable
+ */
+OO.ui.SelectWidget.prototype.addItems = function ( items, index ) {
+       var i, len, item, hash,
+               remove = [];
+
+       for ( i = 0, len = items.length; i < len; i++ ) {
+               item = items[i];
+               hash = OO.getHash( item.getData() );
+               if ( hash in this.hashes ) {
+                       // Remove item with same value
+                       remove.push( this.hashes[hash] );
+               }
+               this.hashes[hash] = item;
+       }
+       if ( remove.length ) {
+               this.removeItems( remove );
+       }
+
+       OO.ui.GroupElement.prototype.addItems.call( this, items, index );
+
+       // Always provide an index, even if it was omitted
+       this.emit( 'add', items, index === undefined ? this.items.length - items.length - 1 : index );
+
+       return this;
+};
+
+/**
+ * Remove items.
+ *
+ * Items will be detached, not removed, so they can be used later.
+ *
+ * @method
+ * @param {OO.ui.OptionWidget[]} items Items to remove
+ * @fires remove
+ * @chainable
+ */
+OO.ui.SelectWidget.prototype.removeItems = function ( items ) {
+       var i, len, item, hash;
+
+       for ( i = 0, len = items.length; i < len; i++ ) {
+               item = items[i];
+               hash = OO.getHash( item.getData() );
+               if ( hash in this.hashes ) {
+                       // Remove existing item
+                       delete this.hashes[hash];
+               }
+               if ( item.isSelected() ) {
+                       this.selectItem( null );
+               }
+       }
+       OO.ui.GroupElement.prototype.removeItems.call( this, items );
+
+       this.emit( 'remove', items );
+
+       return this;
+};
+
+/**
+ * Clear all items.
+ *
+ * Items will be detached, not removed, so they can be used later.
+ *
+ * @method
+ * @fires remove
+ * @chainable
+ */
+OO.ui.SelectWidget.prototype.clearItems = function () {
+       var items = this.items.slice();
+
+       // Clear all items
+       this.hashes = {};
+       OO.ui.GroupElement.prototype.clearItems.call( this );
+       this.selectItem( null );
+
+       this.emit( 'remove', items );
+
+       return this;
+};
+/**
+ * Creates an OO.ui.MenuItemWidget object.
+ *
+ * @class
+ * @extends OO.ui.OptionWidget
+ *
+ * @constructor
+ * @param {Mixed} data Item data
+ * @param {Object} [config] Configuration options
+ */
+OO.ui.MenuItemWidget = function OoUiMenuItemWidget( data, config ) {
+       // Configuration initialization
+       config = $.extend( { 'icon': 'check' }, config );
+
+       // Parent constructor
+       OO.ui.OptionWidget.call( this, data, config );
+
+       // Initialization
+       this.$element.addClass( 'oo-ui-menuItemWidget' );
+};
+
+/* Inheritance */
+
+OO.inheritClass( OO.ui.MenuItemWidget, OO.ui.OptionWidget );
+/**
+ * Create an OO.ui.MenuWidget object.
+ *
+ * @class
+ * @extends OO.ui.SelectWidget
+ * @mixins OO.ui.ClippableElement
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ * @cfg {OO.ui.InputWidget} [input] Input to bind keyboard handlers to
+ */
+OO.ui.MenuWidget = function OoUiMenuWidget( config ) {
+       // Config intialization
+       config = config || {};
+
+       // Parent constructor
+       OO.ui.SelectWidget.call( this, config );
+
+       // Mixin constructors
+       OO.ui.ClippableElement.call( this, this.$group );
+
+       // Properties
+       this.newItems = [];
+       this.$input = config.input ? config.input.$input : null;
+       this.$previousFocus = null;
+       this.isolated = !config.input;
+       this.visible = false;
+       this.onKeyDownHandler = OO.ui.bind( this.onKeyDown, this );
+
+       // Initialization
+       this.$element.hide().addClass( 'oo-ui-menuWidget' );
+};
+
+/* Inheritance */
+
+OO.inheritClass( OO.ui.MenuWidget, OO.ui.SelectWidget );
+
+OO.mixinClass( OO.ui.MenuWidget, OO.ui.ClippableElement );
+
+/* Methods */
+
+/**
+ * Handles key down events.
+ *
+ * @method
+ * @param {jQuery.Event} e Key down event
+ */
+OO.ui.MenuWidget.prototype.onKeyDown = function ( e ) {
+       var nextItem,
+               handled = false,
+               highlightItem = this.getHighlightedItem();
+
+       if ( !this.disabled && this.visible ) {
+               if ( !highlightItem ) {
+                       highlightItem = this.getSelectedItem();
+               }
+               switch ( e.keyCode ) {
+                       case OO.ui.Keys.ENTER:
+                               this.selectItem( highlightItem );
+                               handled = true;
+                               break;
+                       case OO.ui.Keys.UP:
+                               nextItem = this.getRelativeSelectableItem( highlightItem, -1 );
+                               handled = true;
+                               break;
+                       case OO.ui.Keys.DOWN:
+                               nextItem = this.getRelativeSelectableItem( highlightItem, 1 );
+                               handled = true;
+                               break;
+                       case OO.ui.Keys.ESCAPE:
+                               if ( highlightItem ) {
+                                       highlightItem.setHighlighted( false );
+                               }
+                               this.hide();
+                               handled = true;
+                               break;
+               }
+
+               if ( nextItem ) {
+                       this.highlightItem( nextItem );
+                       nextItem.scrollElementIntoView();
+               }
+
+               if ( handled ) {
+                       e.preventDefault();
+                       e.stopPropagation();
+                       return false;
+               }
+       }
+};
+
+/**
+ * Check if the menu is visible.
+ *
+ * @method
+ * @returns {boolean} Menu is visible
+ */
+OO.ui.MenuWidget.prototype.isVisible = function () {
+       return this.visible;
+};
+
+/**
+ * Bind key down listener
+ *
+ * @method
+ */
+OO.ui.MenuWidget.prototype.bindKeyDownListener = function () {
+       if ( this.$input ) {
+               this.$input.on( 'keydown', this.onKeyDownHandler );
+       } else {
+               // Capture menu navigation keys
+               this.getElementWindow().addEventListener( 'keydown', this.onKeyDownHandler, true );
+       }
+};
+
+/**
+ * Unbind key down listener
+ *
+ * @method
+ */
+OO.ui.MenuWidget.prototype.unbindKeyDownListener = function () {
+       if ( this.$input ) {
+               this.$input.off( 'keydown' );
+       } else {
+               this.getElementWindow().removeEventListener( 'keydown', this.onKeyDownHandler, true );
+       }
+};
+
+/**
+ * Select an item.
+ *
+ * The menu will stay open if an item is silently selected.
+ *
+ * @method
+ * @param {OO.ui.OptionWidget} [item] Item to select, omit to deselect all
+ * @chainable
+ */
+OO.ui.MenuWidget.prototype.selectItem = function ( item ) {
+       // Parent method
+       OO.ui.SelectWidget.prototype.selectItem.call( this, item );
+
+       if ( !this.disabled ) {
+               if ( item ) {
+                       this.disabled = true;
+                       item.flash( OO.ui.bind( function () {
+                               this.hide();
+                               this.disabled = false;
+                       }, this ) );
+               } else {
+                       this.hide();
+               }
+       }
+
+       return this;
+};
+
+/**
+ * Add items.
+ *
+ * Adding an existing item (by value) will move it.
+ *
+ * @method
+ * @param {OO.ui.MenuItemWidget[]} items Items to add
+ * @param {number} [index] Index to insert items after
+ * @chainable
+ */
+OO.ui.MenuWidget.prototype.addItems = function ( items, index ) {
+       var i, len, item;
+
+       // Parent method
+       OO.ui.SelectWidget.prototype.addItems.call( this, items, index );
+
+       for ( i = 0, len = items.length; i < len; i++ ) {
+               item = items[i];
+               if ( this.visible ) {
+                       // Defer fitting label until
+                       item.fitLabel();
+               } else {
+                       this.newItems.push( item );
+               }
+       }
+
+       return this;
+};
+
+/**
+ * Show the menu.
+ *
+ * @method
+ * @chainable
+ */
+OO.ui.MenuWidget.prototype.show = function () {
+       var i, len;
+
+       if ( this.items.length ) {
+               this.$element.show();
+               this.visible = true;
+               this.bindKeyDownListener();
+
+               // Change focus to enable keyboard navigation
+               if ( this.isolated && this.$input && !this.$input.is( ':focus' ) ) {
+                       this.$previousFocus = this.$( ':focus' );
+                       this.$input.focus();
+               }
+               if ( this.newItems.length ) {
+                       for ( i = 0, len = this.newItems.length; i < len; i++ ) {
+                               this.newItems[i].fitLabel();
+                       }
+                       this.newItems = [];
+               }
+
+               this.setClipping( true );
+       }
+
+       return this;
+};
+
+/**
+ * Hide the menu.
+ *
+ * @method
+ * @chainable
+ */
+OO.ui.MenuWidget.prototype.hide = function () {
+       this.$element.hide();
+       this.visible = false;
+       this.unbindKeyDownListener();
+
+       if ( this.isolated && this.$previousFocus ) {
+               this.$previousFocus.focus();
+               this.$previousFocus = null;
+       }
+
+       this.setClipping( false );
+
+       return this;
+};
+/**
+ * Creates an OO.ui.MenuSectionItemWidget object.
+ *
+ * @class
+ * @extends OO.ui.OptionWidget
+ *
+ * @constructor
+ * @param {Mixed} data Item data
+ * @param {Object} [config] Configuration options
+ */
+OO.ui.MenuSectionItemWidget = function OoUiMenuSectionItemWidget( data, config ) {
+       // Parent constructor
+       OO.ui.OptionWidget.call( this, data, config );
+
+       // Initialization
+       this.$element.addClass( 'oo-ui-menuSectionItemWidget' );
+};
+
+/* Inheritance */
+
+OO.inheritClass( OO.ui.MenuSectionItemWidget, OO.ui.OptionWidget );
+
+OO.ui.MenuSectionItemWidget.static.selectable = false;
+
+OO.ui.MenuSectionItemWidget.static.highlightable = false;
+/**
+ * Create an OO.ui.OutlineWidget object.
+ *
+ * @class
+ * @extends OO.ui.SelectWidget
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ */
+OO.ui.OutlineWidget = function OoUiOutlineWidget( config ) {
+       // Config intialization
+       config = config || {};
+
+       // Parent constructor
+       OO.ui.SelectWidget.call( this, config );
+
+       // Initialization
+       this.$element.addClass( 'oo-ui-outlineWidget' );
+};
+
+/* Inheritance */
+
+OO.inheritClass( OO.ui.OutlineWidget, OO.ui.SelectWidget );
+/**
+ * Creates an OO.ui.OutlineControlsWidget object.
+ *
+ * @class
+ *
+ * @constructor
+ * @param {OO.ui.OutlineWidget} outline Outline to control
+ * @param {Object} [config] Configuration options
+ * @cfg {Object[]} [adders] List of icons to show as addable item types, each an object with
+ *  name, title and icon properties
+ */
+OO.ui.OutlineControlsWidget = function OoUiOutlineControlsWidget( outline, config ) {
+       // Configuration initialization
+       config = config || {};
+
+       // Parent constructor
+       OO.ui.Widget.call( this, config );
+
+       // Properties
+       this.outline = outline;
+       this.adders = {};
+       this.$adders = this.$( '<div>' );
+       this.$movers = this.$( '<div>' );
+       this.addButton = new OO.ui.ButtonWidget( {
+               '$': this.$,
+               'frameless': true,
+               'icon': 'add-item'
+       } );
+       this.upButton = new OO.ui.ButtonWidget( {
+               '$': this.$,
+               'frameless': true,
+               'icon': 'collapse',
+               'title': OO.ui.msg( 'ooui-outline-control-move-up' )
+       } );
+       this.downButton = new OO.ui.ButtonWidget( {
+               '$': this.$,
+               'frameless': true,
+               'icon': 'expand',
+               'title': OO.ui.msg( 'ooui-outline-control-move-down' )
+       } );
+
+       // Events
+       outline.connect( this, {
+               'select': 'onOutlineChange',
+               'add': 'onOutlineChange',
+               'remove': 'onOutlineChange'
+       } );
+       this.upButton.connect( this, { 'click': ['emit', 'move', -1] } );
+       this.downButton.connect( this, { 'click': ['emit', 'move', 1] } );
+
+       // Initialization
+       this.$element.addClass( 'oo-ui-outlineControlsWidget' );
+       this.$adders.addClass( 'oo-ui-outlineControlsWidget-adders' );
+       this.$movers
+               .addClass( 'oo-ui-outlineControlsWidget-movers' )
+               .append( this.upButton.$element, this.downButton.$element );
+       this.$element.append( this.$adders, this.$movers );
+       if ( config.adders && config.adders.length ) {
+               this.setupAdders( config.adders );
+       }
+};
+
+/* Inheritance */
+
+OO.inheritClass( OO.ui.OutlineControlsWidget, OO.ui.Widget );
+
+/* Events */
+
+/**
+ * @event move
+ * @param {number} places Number of places to move
+ */
+
+/* Methods */
+
+/**
+ * Handle outline change events.
+ *
+ * @method
+ */
+OO.ui.OutlineControlsWidget.prototype.onOutlineChange = function () {
+       var i, len, firstMovable, lastMovable,
+               movable = false,
+               items = this.outline.getItems(),
+               selectedItem = this.outline.getSelectedItem();
+
+       if ( selectedItem && selectedItem.isMovable() ) {
+               movable = true;
+               i = -1;
+               len = items.length;
+               while ( ++i < len ) {
+                       if ( items[i].isMovable() ) {
+                               firstMovable = items[i];
+                               break;
+                       }
+               }
+               i = len;
+               while ( i-- ) {
+                       if ( items[i].isMovable() ) {
+                               lastMovable = items[i];
+                               break;
+                       }
+               }
+       }
+       this.upButton.setDisabled( !movable || selectedItem === firstMovable );
+       this.downButton.setDisabled( !movable || selectedItem === lastMovable );
+};
+
+/**
+ * Setup adders icons.
+ *
+ * @method
+ * @param {Object[]} adders List of configuations for adder buttons, each containing a name, title
+ *  and icon property
+ */
+OO.ui.OutlineControlsWidget.prototype.setupAdders = function ( adders ) {
+       var i, len, addition, button,
+               $buttons = this.$( [] );
+
+       this.$adders.append( this.addButton.$element );
+       for ( i = 0, len = adders.length; i < len; i++ ) {
+               addition = adders[i];
+               button = new OO.ui.ButtonWidget( {
+                       '$': this.$, 'frameless': true, 'icon': addition.icon, 'title': addition.title
+               } );
+               button.connect( this, { 'click': ['emit', 'add', addition.name] } );
+               this.adders[addition.name] = button;
+               this.$adders.append( button.$element );
+               $buttons = $buttons.add( button.$element );
+       }
+};
+/**
+ * Creates an OO.ui.OutlineItemWidget object.
+ *
+ * @class
+ * @extends OO.ui.OptionWidget
+ *
+ * @constructor
+ * @param {Mixed} data Item data
+ * @param {Object} [config] Configuration options
+ * @cfg {number} [level] Indentation level
+ * @cfg {boolean} [movable] Allow modification from outline controls
+ */
+OO.ui.OutlineItemWidget = function OoUiOutlineItemWidget( data, config ) {
+       // Config intialization
+       config = config || {};
+
+       // Parent constructor
+       OO.ui.OptionWidget.call( this, data, config );
+
+       // Properties
+       this.level = 0;
+       this.movable = !!config.movable;
+
+       // Initialization
+       this.$element.addClass( 'oo-ui-outlineItemWidget' );
+       this.setLevel( config.level );
+};
+
+/* Inheritance */
+
+OO.inheritClass( OO.ui.OutlineItemWidget, OO.ui.OptionWidget );
+
+/* Static Properties */
+
+OO.ui.OutlineItemWidget.static.highlightable = false;
+
+OO.ui.OutlineItemWidget.static.scrollIntoViewOnSelect = true;
+
+OO.ui.OutlineItemWidget.static.levelClass = 'oo-ui-outlineItemWidget-level-';
+
+OO.ui.OutlineItemWidget.static.levels = 3;
+
+/* Methods */
+
+/**
+ * Check if item is movable.
+ *
+ * Moveablilty is used by outline controls.
+ *
+ * @returns {boolean} Item is movable
+ */
+OO.ui.OutlineItemWidget.prototype.isMovable = function () {
+       return this.movable;
+};
+
+/**
+ * Get indentation level.
+ *
+ * @returns {number} Indentation level
+ */
+OO.ui.OutlineItemWidget.prototype.getLevel = function () {
+       return this.level;
+};
+
+/**
+ * Set indentation level.
+ *
+ * @method
+ * @param {number} [level=0] Indentation level, in the range of [0,#maxLevel]
+ * @chainable
+ */
+OO.ui.OutlineItemWidget.prototype.setLevel = function ( level ) {
+       var levels = this.constructor.static.levels,
+               levelClass = this.constructor.static.levelClass,
+               i = levels;
+
+       this.level = level ? Math.max( 0, Math.min( levels - 1, level ) ) : 0;
+       while ( i-- ) {
+               if ( this.level === i ) {
+                       this.$element.addClass( levelClass + i );
+               } else {
+                       this.$element.removeClass( levelClass + i );
+               }
+       }
+
+       return this;
+};
+/**
+ * Creates an OO.ui.BookletOutlineItemWidget object.
+ *
+ * @class
+ * @extends OO.ui.OutlineItemWidget
+ *
+ * @constructor
+ * @param {Mixed} data Item data
+ * @param {Object} [config] Configuration options
+ */
+OO.ui.BookletOutlineItemWidget = function OoUiBookletOutlineItemWidget( data, page, config ) {
+       // Configuration intialization
+       config = $.extend( {
+               'label': page.getLabel() || data,
+               'level': page.getLevel(),
+               'icon': page.getIcon(),
+               'indicator': page.getIndicator(),
+               'indicatorTitle': page.getIndicatorTitle(),
+               'movable': page.isMovable()
+       }, config );
+
+       // Parent constructor
+       OO.ui.OutlineItemWidget.call( this, data, config );
+
+       // Initialization
+       this.$element.addClass( 'oo-ui-bookletOutlineItemWidget' );
+};
+
+/* Inheritance */
+
+OO.inheritClass( OO.ui.BookletOutlineItemWidget, OO.ui.OutlineItemWidget );
+/**
+ * Create an OO.ui.ButtonSelect object.
+ *
+ * @class
+ * @extends OO.ui.OptionWidget
+ * @mixins OO.ui.ButtonedElement
+ * @mixins OO.ui.FlaggableElement
+ *
+ * @constructor
+ * @param {Mixed} data Option data
+ * @param {Object} [config] Configuration options
+ */
+OO.ui.ButtonOptionWidget = function OoUiButtonOptionWidget( data, config ) {
+       // Parent constructor
+       OO.ui.OptionWidget.call( this, data, config );
+
+       // Mixin constructors
+       OO.ui.ButtonedElement.call( this, this.$( '<a>' ), config );
+       OO.ui.FlaggableElement.call( this, config );
+
+       // Initialization
+       this.$element.addClass( 'oo-ui-buttonOptionWidget' );
+       this.$button.append( this.$element.contents() );
+       this.$element.append( this.$button );
+};
+
+/* Inheritance */
+
+OO.inheritClass( OO.ui.ButtonOptionWidget, OO.ui.OptionWidget );
+
+OO.mixinClass( OO.ui.ButtonOptionWidget, OO.ui.ButtonedElement );
+OO.mixinClass( OO.ui.ButtonOptionWidget, OO.ui.FlaggableElement );
+
+/* Methods */
+
+/**
+ * @inheritdoc
+ */
+OO.ui.ButtonOptionWidget.prototype.setSelected = function ( state ) {
+       OO.ui.OptionWidget.prototype.setSelected.call( this, state );
+
+       this.setActive( state );
+
+       return this;
+};
+/**
+ * Create an OO.ui.ButtonSelect object.
+ *
+ * @class
+ * @extends OO.ui.SelectWidget
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ */
+OO.ui.ButtonSelectWidget = function OoUiButtonSelectWidget( config ) {
+       // Parent constructor
+       OO.ui.SelectWidget.call( this, config );
+
+       // Initialization
+       this.$element.addClass( 'oo-ui-buttonSelectWidget' );
+};
+
+/* Inheritance */
+
+OO.inheritClass( OO.ui.ButtonSelectWidget, OO.ui.SelectWidget );
+/**
+ * Creates an OO.ui.PopupWidget object.
+ *
+ * @class
+ * @extends OO.ui.Widget
+ * @mixins OO.ui.LabeledElement
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ * @cfg {boolean} [tail=true] Show tail pointing to origin of popup
+ * @cfg {string} [align='center'] Alignment of popup to origin
+ * @cfg {jQuery} [$container] Container to prevent popup from rendering outside of
+ * @cfg {boolean} [autoClose=false] Popup auto-closes when it loses focus
+ * @cfg {jQuery} [$autoCloseIgnore] Elements to not auto close when clicked
+ * @cfg {boolean} [head] Show label and close button at the top
+ */
+OO.ui.PopupWidget = function OoUiPopupWidget( config ) {
+       // Config intialization
+       config = config || {};
+
+       // Parent constructor
+       OO.ui.Widget.call( this, config );
+
+       // Mixin constructors
+       OO.ui.LabeledElement.call( this, this.$( '<div>' ), config );
+
+       // Properties
+       this.visible = false;
+       this.$popup = this.$( '<div>' );
+       this.$head = this.$( '<div>' );
+       this.$body = this.$( '<div>' );
+       this.$tail = this.$( '<div>' );
+       this.$container = config.$container || this.$( 'body' );
+       this.autoClose = !!config.autoClose;
+       this.$autoCloseIgnore = config.$autoCloseIgnore;
+       this.transitionTimeout = null;
+       this.tail = false;
+       this.align = config.align || 'center';
+       this.closeButton = new OO.ui.ButtonWidget( { '$': this.$, 'frameless': true, 'icon': 'close' } );
+       this.onMouseDownHandler = OO.ui.bind( this.onMouseDown, this );
+
+       // Events
+       this.closeButton.connect( this, { 'click': 'onCloseButtonClick' } );
+
+       // Initialization
+       this.useTail( config.tail !== undefined ? !!config.tail : true );
+       this.$body.addClass( 'oo-ui-popupWidget-body' );
+       this.$tail.addClass( 'oo-ui-popupWidget-tail' );
+       this.$head
+               .addClass( 'oo-ui-popupWidget-head' )
+               .append( this.$label, this.closeButton.$element );
+       if ( !config.head ) {
+               this.$head.hide();
+       }
+       this.$popup
+               .addClass( 'oo-ui-popupWidget-popup' )
+               .append( this.$head, this.$body );
+       this.$element.hide()
+               .addClass( 'oo-ui-popupWidget' )
+               .append( this.$popup, this.$tail );
+};
+
+/* Inheritance */
+
+OO.inheritClass( OO.ui.PopupWidget, OO.ui.Widget );
+
+OO.mixinClass( OO.ui.PopupWidget, OO.ui.LabeledElement );
+
+/* Events */
+
+/**
+ * @event hide
+ */
+
+/**
+ * @event show
+ */
+
+/* Methods */
+
+/**
+ * Handles mouse down events.
+ *
+ * @method
+ * @param {jQuery.Event} e Mouse down event
+ */
+OO.ui.PopupWidget.prototype.onMouseDown = function ( e ) {
+       if (
+               this.visible &&
+               !$.contains( this.$element[0], e.target ) &&
+               ( !this.$autoCloseIgnore || !this.$autoCloseIgnore.has( e.target ).length )
+       ) {
+               this.hide();
+       }
+};
+
+/**
+ * Bind mouse down listener
+ *
+ * @method
+ */
+OO.ui.PopupWidget.prototype.bindMouseDownListener = function () {
+       // Capture clicks outside popup
+       this.getElementWindow().addEventListener( 'mousedown', this.onMouseDownHandler, true );
+};
+
+/**
+ * Handles close button click events.
+ *
+ * @method
+ */
+OO.ui.PopupWidget.prototype.onCloseButtonClick = function () {
+       if ( this.visible ) {
+               this.hide();
+       }
+};
+
+/**
+ * Unbind mouse down listener
+ *
+ * @method
+ */
+OO.ui.PopupWidget.prototype.unbindMouseDownListener = function () {
+       this.getElementWindow().removeEventListener( 'mousedown', this.onMouseDownHandler, true );
+};
+
+/**
+ * Check if the popup is visible.
+ *
+ * @method
+ * @returns {boolean} Popup is visible
+ */
+OO.ui.PopupWidget.prototype.isVisible = function () {
+       return this.visible;
+};
+
+/**
+ * Set whether to show a tail.
+ *
+ * @method
+ * @returns {boolean} Make tail visible
+ */
+OO.ui.PopupWidget.prototype.useTail = function ( value ) {
+       value = !!value;
+       if ( this.tail !== value ) {
+               this.tail = value;
+               if ( value ) {
+                       this.$element.addClass( 'oo-ui-popupWidget-tailed' );
+               } else {
+                       this.$element.removeClass( 'oo-ui-popupWidget-tailed' );
+               }
+       }
+};
+
+/**
+ * Check if showing a tail.
+ *
+ * @method
+ * @returns {boolean} tail is visible
+ */
+OO.ui.PopupWidget.prototype.hasTail = function () {
+       return this.tail;
+};
+
+/**
+ * Show the context.
+ *
+ * @method
+ * @fires show
+ * @chainable
+ */
+OO.ui.PopupWidget.prototype.show = function () {
+       if ( !this.visible ) {
+               this.$element.show();
+               this.visible = true;
+               this.emit( 'show' );
+               if ( this.autoClose ) {
+                       this.bindMouseDownListener();
+               }
+       }
+       return this;
+};
+
+/**
+ * Hide the context.
+ *
+ * @method
+ * @fires hide
+ * @chainable
+ */
+OO.ui.PopupWidget.prototype.hide = function () {
+       if ( this.visible ) {
+               this.$element.hide();
+               this.visible = false;
+               this.emit( 'hide' );
+               if ( this.autoClose ) {
+                       this.unbindMouseDownListener();
+               }
+       }
+       return this;
+};
+
+/**
+ * Updates the position and size.
+ *
+ * @method
+ * @param {number} width Width
+ * @param {number} height Height
+ * @param {boolean} [transition=false] Use a smooth transition
+ * @chainable
+ */
+OO.ui.PopupWidget.prototype.display = function ( width, height, transition ) {
+       var padding = 10,
+               originOffset = Math.round( this.$element.offset().left ),
+               containerLeft = Math.round( this.$container.offset().left ),
+               containerWidth = this.$container.innerWidth(),
+               containerRight = containerLeft + containerWidth,
+               popupOffset = width * ( { 'left': 0, 'center': -0.5, 'right': -1 } )[this.align],
+               popupLeft = popupOffset - padding,
+               popupRight = popupOffset + padding + width + padding,
+               overlapLeft = ( originOffset + popupLeft ) - containerLeft,
+               overlapRight = containerRight - ( originOffset + popupRight );
+
+       // Prevent transition from being interrupted
+       clearTimeout( this.transitionTimeout );
+       if ( transition ) {
+               // Enable transition
+               this.$element.addClass( 'oo-ui-popupWidget-transitioning' );
+       }
+
+       if ( overlapRight < 0 ) {
+               popupOffset += overlapRight;
+       } else if ( overlapLeft < 0 ) {
+               popupOffset -= overlapLeft;
+       }
+
+       // Position body relative to anchor and resize
+       this.$popup.css( {
+               'left': popupOffset,
+               'width': width,
+               'height': height === undefined ? 'auto' : height
+       } );
+
+       if ( transition ) {
+               // Prevent transitioning after transition is complete
+               this.transitionTimeout = setTimeout( OO.ui.bind( function () {
+                       this.$element.removeClass( 'oo-ui-popupWidget-transitioning' );
+               }, this ), 200 );
+       } else {
+               // Prevent transitioning immediately
+               this.$element.removeClass( 'oo-ui-popupWidget-transitioning' );
+       }
+
+       return this;
+};
+/**
+ * Button that shows and hides a popup.
+ *
+ * @class
+ * @extends OO.ui.ButtonWidget
+ * @mixins OO.ui.PopuppableElement
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ */
+OO.ui.PopupButtonWidget = function OoUiPopupButtonWidget( config ) {
+       // Parent constructor
+       OO.ui.ButtonWidget.call( this, config );
+
+       // Mixin constructors
+       OO.ui.PopuppableElement.call( this, config );
+
+       // Initialization
+       this.$element
+               .addClass( 'oo-ui-popupButtonWidget' )
+               .append( this.popup.$element );
+};
+
+/* Inheritance */
+
+OO.inheritClass( OO.ui.PopupButtonWidget, OO.ui.ButtonWidget );
+
+OO.mixinClass( OO.ui.PopupButtonWidget, OO.ui.PopuppableElement );
+
+/* Methods */
+
+/**
+ * Handles mouse click events.
+ *
+ * @method
+ * @param {jQuery.Event} e Mouse click event
+ */
+OO.ui.PopupButtonWidget.prototype.onClick = function ( e ) {
+       // Skip clicks within the popup
+       if ( $.contains( this.popup.$element[0], e.target ) ) {
+               return;
+       }
+
+       if ( !this.disabled ) {
+               if ( this.popup.isVisible() ) {
+                       this.hidePopup();
+               } else {
+                       this.showPopup();
+               }
+               OO.ui.ButtonWidget.prototype.onClick.call( this );
+       }
+       return false;
+};
+/**
+ * Creates an OO.ui.SearchWidget object.
+ *
+ * @class
+ * @extends OO.ui.Widget
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ * @cfg {string|jQuery} [placeholder] Placeholder text for query input
+ * @cfg {string} [value] Initial query value
+ */
+OO.ui.SearchWidget = function OoUiSearchWidget( config ) {
+       // Configuration intialization
+       config = config || {};
+
+       // Parent constructor
+       OO.ui.Widget.call( this, config );
+
+       // Properties
+       this.query = new OO.ui.TextInputWidget( {
+               '$': this.$,
+               'icon': 'search',
+               'placeholder': config.placeholder,
+               'value': config.value
+       } );
+       this.results = new OO.ui.SelectWidget( { '$': this.$ } );
+       this.$query = this.$( '<div>' );
+       this.$results = this.$( '<div>' );
+
+       // Events
+       this.query.connect( this, {
+               'change': 'onQueryChange',
+               'enter': 'onQueryEnter'
+       } );
+       this.results.connect( this, {
+               'highlight': 'onResultsHighlight',
+               'select': 'onResultsSelect'
+       } );
+       this.query.$input.on( 'keydown', OO.ui.bind( this.onQueryKeydown, this ) );
+
+       // Initialization
+       this.$query
+               .addClass( 'oo-ui-searchWidget-query' )
+               .append( this.query.$element );
+       this.$results
+               .addClass( 'oo-ui-searchWidget-results' )
+               .append( this.results.$element );
+       this.$element
+               .addClass( 'oo-ui-searchWidget' )
+               .append( this.$results, this.$query );
+};
+
+/* Inheritance */
+
+OO.inheritClass( OO.ui.SearchWidget, OO.ui.Widget );
+
+/* Events */
+
+/**
+ * @event highlight
+ * @param {Object|null} item Item data or null if no item is highlighted
+ */
+
+/**
+ * @event select
+ * @param {Object|null} item Item data or null if no item is selected
+ */
+
+/* Methods */
+
+/**
+ * Handle query key down events.
+ *
+ * @method
+ * @param {jQuery.Event} e Key down event
+ */
+OO.ui.SearchWidget.prototype.onQueryKeydown = function ( e ) {
+       var highlightedItem, nextItem,
+               dir = e.which === OO.ui.Keys.DOWN ? 1 : ( e.which === OO.ui.Keys.UP ? -1 : 0 );
+
+       if ( dir ) {
+               highlightedItem = this.results.getHighlightedItem();
+               if ( !highlightedItem ) {
+                       highlightedItem = this.results.getSelectedItem();
+               }
+               nextItem = this.results.getRelativeSelectableItem( highlightedItem, dir );
+               this.results.highlightItem( nextItem );
+               nextItem.scrollElementIntoView();
+       }
+};
+
+/**
+ * Handle select widget select events.
+ *
+ * Clears existing results. Subclasses should repopulate items according to new query.
+ *
+ * @method
+ * @param {string} value New value
+ */
+OO.ui.SearchWidget.prototype.onQueryChange = function () {
+       // Reset
+       this.results.clearItems();
+};
+
+/**
+ * Handle select widget enter key events.
+ *
+ * Selects highlighted item.
+ *
+ * @method
+ * @param {string} value New value
+ */
+OO.ui.SearchWidget.prototype.onQueryEnter = function () {
+       // Reset
+       this.results.selectItem( this.results.getHighlightedItem() );
+};
+
+/**
+ * Handle select widget highlight events.
+ *
+ * @method
+ * @param {OO.ui.OptionWidget} item Highlighted item
+ * @fires highlight
+ */
+OO.ui.SearchWidget.prototype.onResultsHighlight = function ( item ) {
+       this.emit( 'highlight', item ? item.getData() : null );
+};
+
+/**
+ * Handle select widget select events.
+ *
+ * @method
+ * @param {OO.ui.OptionWidget} item Selected item
+ * @fires select
+ */
+OO.ui.SearchWidget.prototype.onResultsSelect = function ( item ) {
+       this.emit( 'select', item ? item.getData() : null );
+};
+
+/**
+ * Get the query input.
+ *
+ * @method
+ * @returns {OO.ui.TextInputWidget} Query input
+ */
+OO.ui.SearchWidget.prototype.getQuery = function () {
+       return this.query;
+};
+
+/**
+ * Get the results list.
+ *
+ * @method
+ * @returns {OO.ui.SelectWidget} Select list
+ */
+OO.ui.SearchWidget.prototype.getResults = function () {
+       return this.results;
+};
+/**
+ * Creates an OO.ui.TextInputWidget object.
+ *
+ * @class
+ * @extends OO.ui.InputWidget
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ * @cfg {string} [placeholder] Placeholder text
+ * @cfg {string} [icon] Symbolic name of icon
+ * @cfg {boolean} [multiline=false] Allow multiple lines of text
+ */
+OO.ui.TextInputWidget = function OoUiTextInputWidget( config ) {
+       config = config || {};
+
+       // Parent constructor
+       OO.ui.InputWidget.call( this, config );
+
+       // Properties
+       this.pending = 0;
+       this.multiline = !!config.multiline;
+
+       // Events
+       this.$input.on( 'keypress', OO.ui.bind( this.onKeyPress, this ) );
+
+       // Initialization
+       this.$element.addClass( 'oo-ui-textInputWidget' );
+       if ( config.icon ) {
+               this.$element.addClass( 'oo-ui-textInputWidget-decorated' );
+               this.$element.append(
+                       this.$( '<span>' )
+                               .addClass( 'oo-ui-textInputWidget-icon oo-ui-icon-' + config.icon )
+                               .mousedown( OO.ui.bind( function () {
+                                       this.$input.focus();
+                                       return false;
+                               }, this ) )
+               );
+       }
+       if ( config.placeholder ) {
+               this.$input.attr( 'placeholder', config.placeholder );
+       }
+};
+
+/* Inheritance */
+
+OO.inheritClass( OO.ui.TextInputWidget, OO.ui.InputWidget );
+
+/* Events */
+
+/**
+ * User presses enter inside the text box.
+ *
+ * Not called if input is multiline.
+ *
+ * @event enter
+ */
+
+/* Methods */
+
+/**
+ * Handles key press events.
+ *
+ * @param {jQuery.Event} e Key press event
+ * @fires enter If enter key is pressed and input is not multiline
+ */
+OO.ui.TextInputWidget.prototype.onKeyPress = function ( e ) {
+       if ( e.which === OO.ui.Keys.ENTER && !this.multiline ) {
+               this.emit( 'enter' );
+       }
+};
+
+/**
+ * Get input element.
+ *
+ * @method
+ * @param {Object} [config] Configuration options
+ * @returns {jQuery} Input element
+ */
+OO.ui.TextInputWidget.prototype.getInputElement = function ( config ) {
+       return config.multiline ? this.$( '<textarea>' ) : this.$( '<input type="text" />' );
+};
+
+/* Methods */
+
+/**
+ * Checks if input is pending.
+ *
+ * @method
+ * @returns {boolean} Input is pending
+ */
+OO.ui.TextInputWidget.prototype.isPending = function () {
+       return !!this.pending;
+};
+
+/**
+ * Increases the pending stack.
+ *
+ * @method
+ * @chainable
+ */
+OO.ui.TextInputWidget.prototype.pushPending = function () {
+       this.pending++;
+       this.$element.addClass( 'oo-ui-textInputWidget-pending' );
+       this.$input.addClass( 'oo-ui-texture-pending' );
+       return this;
+};
+
+/**
+ * Reduces the pending stack.
+ *
+ * Clamped at zero.
+ *
+ * @method
+ * @chainable
+ */
+OO.ui.TextInputWidget.prototype.popPending = function () {
+       this.pending = Math.max( 0, this.pending - 1 );
+       if ( !this.pending ) {
+               this.$element.removeClass( 'oo-ui-textInputWidget-pending' );
+               this.$input.removeClass( 'oo-ui-texture-pending' );
+       }
+       return this;
+};
+/**
+ * Creates an OO.ui.TextInputMenuWidget object.
+ *
+ * @class
+ * @extends OO.ui.MenuWidget
+ *
+ * @constructor
+ * @param {OO.ui.TextInputWidget} input Text input widget to provide menu for
+ * @param {Object} [config] Configuration options
+ * @cfg {jQuery} [$container=input.$element] Element to render menu under
+ */
+OO.ui.TextInputMenuWidget = function OoUiTextInputMenuWidget( input, config ) {
+       // Parent constructor
+       OO.ui.MenuWidget.call( this, config );
+
+       // Properties
+       this.input = input;
+       this.$container = config.$container || this.input.$element;
+       this.onWindowResizeHandler = OO.ui.bind( this.onWindowResize, this );
+
+       // Initialization
+       this.$element.addClass( 'oo-ui-textInputMenuWidget' );
+};
+
+/* Inheritance */
+
+OO.inheritClass( OO.ui.TextInputMenuWidget, OO.ui.MenuWidget );
+
+/* Methods */
+
+/**
+ * Handle window resize event.
+ *
+ * @method
+ * @param {jQuery.Event} e Window resize event
+ */
+OO.ui.TextInputMenuWidget.prototype.onWindowResize = function () {
+       this.position();
+};
+
+/**
+ * Shows the menu.
+ *
+ * @method
+ * @chainable
+ */
+OO.ui.TextInputMenuWidget.prototype.show = function () {
+       // Parent method
+       OO.ui.MenuWidget.prototype.show.call( this );
+
+       this.position();
+       this.$( this.getElementWindow() ).on( 'resize', this.onWindowResizeHandler );
+       return this;
+};
+
+/**
+ * Hides the menu.
+ *
+ * @method
+ * @chainable
+ */
+OO.ui.TextInputMenuWidget.prototype.hide = function () {
+       // Parent method
+       OO.ui.MenuWidget.prototype.hide.call( this );
+
+       this.$( this.getElementWindow() ).off( 'resize', this.onWindowResizeHandler );
+       return this;
+};
+
+/**
+ * Positions the menu.
+ *
+ * @method
+ * @chainable
+ */
+OO.ui.TextInputMenuWidget.prototype.position = function () {
+       var frameOffset,
+               $container = this.$container,
+               dimensions = $container.offset();
+
+       // Position under input
+       dimensions.top += $container.height();
+
+       // Compensate for frame position if in a differnt frame
+       if ( this.input.$.frame && this.input.$.context !== this.$element[0].ownerDocument ) {
+               frameOffset = OO.ui.Element.getRelativePosition(
+                       this.input.$.frame.$element, this.$element.offsetParent()
+               );
+               dimensions.left += frameOffset.left;
+               dimensions.top += frameOffset.top;
+       } else {
+               // Fix for RTL (for some reason, no need to fix if the frameoffset is set)
+               if ( this.$element.css( 'direction' ) === 'rtl' ) {
+                       dimensions.right = this.$element.parent().position().left -
+                               dimensions.width - dimensions.left;
+                       // Erase the value for 'left':
+                       delete dimensions.left;
+               }
+       }
+
+       this.$element.css( dimensions );
+       this.setIdealSize( $container.width() );
+       return this;
+};
+/**
+ * Mixin for widgets with a boolean state.
+ *
+ * @class
+ * @abstract
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ * @cfg {boolean} [value=false] Initial value
+ */
+OO.ui.ToggleWidget = function OoUiToggleWidget( config ) {
+       // Configuration initialization
+       config = config || {};
+
+       // Properties
+       this.value = null;
+
+       // Initialization
+       this.$element.addClass( 'oo-ui-toggleWidget' );
+       this.setValue( !!config.value );
+};
+
+/* Events */
+
+/**
+ * @event change
+ * @param {boolean} value Changed value
+ */
+
+/* Methods */
+
+/**
+ * Get the value of the toggle.
+ *
+ * @method
+ * @returns {boolean} Toggle value
+ */
+OO.ui.ToggleWidget.prototype.getValue = function () {
+       return this.value;
+};
+
+/**
+ * Set the value of the toggle.
+ *
+ * @method
+ * @param {boolean} value New value
+ * @fires change
+ * @chainable
+ */
+OO.ui.ToggleWidget.prototype.setValue = function ( value ) {
+       value = !!value;
+       if ( this.value !== value ) {
+               this.value = value;
+               this.emit( 'change', value );
+               this.$element.toggleClass( 'oo-ui-toggleWidget-on', value );
+               this.$element.toggleClass( 'oo-ui-toggleWidget-off', !value );
+       }
+       return this;
+};
+/**
+ * @class
+ * @extends OO.ui.ButtonWidget
+ * @mixins OO.ui.ToggleWidget
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ * @cfg {boolean} [value=false] Initial value
+ */
+OO.ui.ToggleButtonWidget = function OoUiToggleButtonWidget( config ) {
+       // Configuration initialization
+       config = config || {};
+
+       // Parent constructor
+       OO.ui.ButtonWidget.call( this, config );
+
+       // Mixin constructors
+       OO.ui.ToggleWidget.call( this, config );
+
+       // Initialization
+       this.$element.addClass( 'oo-ui-toggleButtonWidget' );
+};
+
+/* Inheritance */
+
+OO.inheritClass( OO.ui.ToggleButtonWidget, OO.ui.ButtonWidget );
+
+OO.mixinClass( OO.ui.ToggleButtonWidget, OO.ui.ToggleWidget );
+
+/* Methods */
+
+/**
+ * @inheritdoc
+ */
+OO.ui.ToggleButtonWidget.prototype.onClick = function () {
+       if ( !this.disabled ) {
+               this.setValue( !this.value );
+       }
+
+       // Parent method
+       return OO.ui.ButtonWidget.prototype.onClick.call( this );
+};
+
+/**
+ * @inheritdoc
+ */
+OO.ui.ToggleButtonWidget.prototype.setValue = function ( value ) {
+       value = !!value;
+       if ( value !== this.value ) {
+               this.setActive( value );
+       }
+
+       // Parent method
+       OO.ui.ToggleWidget.prototype.setValue.call( this, value );
+
+       return this;
+};
+/**
+ * @class
+ * @abstract
+ * @extends OO.ui.Widget
+ * @mixins OO.ui.ToggleWidget
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ * @cfg {boolean} [value=false] Initial value
+ */
+OO.ui.ToggleSwitchWidget = function OoUiToggleSwitchWidget( config ) {
+       // Parent constructor
+       OO.ui.Widget.call( this, config );
+
+       // Mixin constructors
+       OO.ui.ToggleWidget.call( this, config );
+
+       // Properties
+       this.dragging = false;
+       this.dragStart = null;
+       this.sliding = false;
+       this.$on = this.$( '<span>' );
+       this.$grip = this.$( '<span>' );
+
+       // Events
+       this.$element.on( 'click', OO.ui.bind( this.onClick, this ) );
+
+       // Initialization
+       this.$on.addClass( 'oo-ui-toggleSwitchWidget-on' );
+       this.$grip.addClass( 'oo-ui-toggleSwitchWidget-grip' );
+       this.$element
+               .addClass( 'oo-ui-toggleSwitchWidget' )
+               .append( this.$on, this.$grip );
+};
+
+/* Inheritance */
+
+OO.inheritClass( OO.ui.ToggleSwitchWidget, OO.ui.Widget );
+
+OO.mixinClass( OO.ui.ToggleSwitchWidget, OO.ui.ToggleWidget );
+
+/* Methods */
+
+/**
+ * Handles mouse down events.
+ *
+ * @method
+ * @param {jQuery.Event} e Mouse down event
+ */
+OO.ui.ToggleSwitchWidget.prototype.onClick = function ( e ) {
+       if ( !this.disabled && e.which === 1 ) {
+               this.setValue( !this.value );
+       }
+};
+}() );
diff --git a/resources/oojs-ui/oojs-ui.svg.css b/resources/oojs-ui/oojs-ui.svg.css
new file mode 100644 (file)
index 0000000..be512dd
--- /dev/null
@@ -0,0 +1,1745 @@
+/*!
+ * OOjs UI v0.1.0-pre-svg (7788dc6700)
+ * https://www.mediawiki.org/wiki/OOjs_UI
+ *
+ * Copyright 2011–2014 OOjs Team and other contributors.
+ * Released under the MIT license
+ * http://oojs.mit-license.org
+ *
+ * Date: Thu Feb 13 2014 13:56:07 GMT-0800 (PST)
+ */
+/*csslint vendor-prefix:false */
+
+/* Textures */
+
+.oo-ui-texture-pending {
+       /* @embed */
+       background-image: url(images/textures/pending.gif);
+}
+
+.oo-ui-texture-transparency {
+       /* @embed */
+       background-image: url(images/textures/transparency.png);
+}
+
+/* Animation */
+
+@-webkit-keyframes oo-ui-zoom-in {
+       from { -webkit-transform: scale(0.5); }
+       to { -webkit-transform: scale(1); }
+}
+
+@-moz-keyframes oo-ui-zoom-in {
+       from { -moz-transform: scale(0.5); }
+       to { -moz-transform: scale(1); }
+}
+
+@-o-keyframes oo-ui-zoom-in {
+       from { -o-transform: scale(0.5); }
+       to { -o-transform: scale(1); }
+}
+
+@keyframes oo-ui-zoom-in {
+       from { transform: scale(0.5); }
+       to { transform: scale(1); }
+}
+
+@-webkit-keyframes oo-ui-fade-in {
+       from { opacity: 0; }
+       to { opacity: 1; }
+}
+
+@-moz-keyframes oo-ui-fade-in {
+       from { opacity: 0; }
+       to { opacity: 1; }
+}
+
+@-o-keyframes oo-ui-fade-in {
+       from { opacity: 0; }
+       to { opacity: 1; }
+}
+
+@keyframes oo-ui-fade-in {
+       from { opacity: 0; }
+       to { opacity: 1; }
+}
+
+/* RTL Definitions */
+
+/* @noflip */
+.oo-ui-rtl {
+       direction: rtl;
+}
+/* @noflip */
+.oo-ui-ltr {
+       direction: ltr;
+}
+.oo-ui-dialog {
+       position: fixed;
+       top: 0;
+       right: 0;
+       bottom: 0;
+       left: 0;
+       padding: 1em;
+       line-height: 1em;
+       background-color: #fff;
+       background-color: rgba(255,255,255,0.5);
+       -webkit-animation: oo-ui-fade-in 250ms ease-in-out 0 1 normal;
+       -moz-animation: oo-ui-fade-in 250ms ease-in-out 0 1 normal;
+       -o-animation: oo-ui-fade-in 250ms ease-in-out 0 1 normal;
+       animation: oo-ui-fade-in 250ms ease-in-out 0 1 normal;
+}
+
+.oo-ui-dialog-closing {
+       -webkit-animation: oo-ui-fade-in 250ms ease-in-out 0 1 reverse;
+       -moz-animation: oo-ui-fade-in 250ms ease-in-out 0 1 reverse;
+       -o-animation: oo-ui-fade-in 250ms ease-in-out 0 1 reverse;
+       animation: oo-ui-fade-in 250ms ease-in-out 0 1 reverse;
+}
+
+.oo-ui-dialog .oo-ui-window-frame {
+       position: fixed;
+       top: 1em;
+       right: 0;
+       bottom: 1em;
+       left: 0;
+       margin: auto;
+       width: 800px;
+       min-height: 12em;
+       max-height: 600px;
+       background-color: #fff;
+       border: solid 1px #ccc;
+       border-radius: 0.5em;
+       box-shadow: 0 0.2em 1em rgba(0, 0, 0, 0.3);
+       overflow: hidden;
+       -webkit-animation: oo-ui-zoom-in 250ms ease-in-out 0 1 normal;
+       -moz-animation: oo-ui-zoom-in 250ms ease-in-out 0 1 normal;
+       -o-animation: oo-ui-zoom-in 250ms ease-in-out 0 1 normal;
+       animation: oo-ui-zoom-in 250ms ease-in-out 0 1 normal;
+}
+
+.oo-ui-dialog .oo-ui-window-frame.oo-ui-window-frame-small {
+       max-width: 600px;
+       max-height: 400px;
+}
+
+.oo-ui-dialog-closing .oo-ui-window-frame {
+       -webkit-animation: oo-ui-zoom-in 250ms ease-in-out 0 1 reverse;
+       -moz-animation: oo-ui-zoom-in 250ms ease-in-out 0 1 reverse;
+       -o-animation: oo-ui-zoom-in 250ms ease-in-out 0 1 reverse;
+       animation: oo-ui-zoom-in 250ms ease-in-out 0 1 reverse;
+}
+
+.oo-ui-dialog .oo-ui-frame {
+       width: 100%;
+       height: 100%;
+}
+
+.oo-ui-dialog-content .oo-ui-window-head,
+.oo-ui-dialog-content .oo-ui-window-body,
+.oo-ui-dialog-content .oo-ui-window-foot {
+       position: absolute;
+       left: 0;
+       right: 0;
+       -webkit-box-sizing: border-box;
+       -moz-box-sizing: border-box;
+       box-sizing: border-box;
+       overflow: hidden;
+}
+
+.oo-ui-dialog-content .oo-ui-window-head {
+       top: 0;
+       height: 3.8em;
+       padding: 0.5em;
+}
+
+.oo-ui-dialog-content .oo-ui-window-foot {
+       bottom: 0;
+       height: 4.8em;
+       padding: 1em;
+}
+
+.oo-ui-dialog-content .oo-ui-window-body {
+       box-shadow: 0 0 0.66em rgba(0,0,0,0.25);
+       top: 3.8em;
+       bottom: 4.8em;
+}
+
+.oo-ui-dialog-content-footless .oo-ui-window-body {
+       bottom: 0;
+}
+
+.oo-ui-dialog-content-footless .oo-ui-window-foot {
+       display: none;
+}
+
+.oo-ui-dialog-content .oo-ui-window-icon {
+       width: 2.4em;
+       height: 2.8em;
+       line-height: 2.8em;
+}
+
+.oo-ui-dialog-content .oo-ui-window-title {
+       line-height: 2.8em;
+}
+
+.oo-ui-dialog-content .oo-ui-window-foot .oo-ui-buttonedElement-framed {
+       float: left;
+       margin: 0.125em 0.25em;
+}
+
+.oo-ui-dialog-content .oo-ui-window-foot .oo-ui-buttonedElement-framed.oo-ui-flaggableElement-primary,
+.oo-ui-dialog-content .oo-ui-window-foot .oo-ui-buttonedElement-framed.oo-ui-flaggableElement-constructive,
+.oo-ui-dialog-content .oo-ui-window-foot .oo-ui-buttonedElement-framed.oo-ui-flaggableElement-destructive {
+       float: right;
+}
+
+.oo-ui-dialog-content .oo-ui-window-closeButton {
+       float: right;
+       margin: 0.25em 0.25em;
+}
+
+/* OO.ui.ButtonedElement */
+
+a.oo-ui-buttonedElement-button {
+       color: #333;
+       cursor: pointer;
+       display: inline-block;
+       vertical-align: middle;
+       -webkit-touch-callout: none;
+       -webkit-user-select: none;
+       -moz-user-select: none;
+       -ms-user-select: none;
+       user-select: none;
+}
+
+.oo-ui-buttonedElement .oo-ui-buttonedElement-button > .oo-ui-indicatedElement-indicator,
+.oo-ui-buttonedElement .oo-ui-buttonedElement-button > .oo-ui-iconedElement-icon {
+       display: none;
+}
+
+.oo-ui-buttonedElement.oo-ui-indicatedElement .oo-ui-buttonedElement-button > .oo-ui-indicatedElement-indicator,
+.oo-ui-buttonedElement.oo-ui-iconedElement .oo-ui-buttonedElement-button > .oo-ui-iconedElement-icon {
+       opacity: 0.8;
+       display: inline-block;
+       vertical-align: middle;
+       background-position: center center;
+       background-repeat: no-repeat;
+       width: 1.9em;
+       height: 1.9em;
+}
+
+.oo-ui-buttonedElement .oo-ui-buttonedElement-button > .oo-ui-iconedElement-icon {
+       margin-left: 0;
+}
+
+.oo-ui-buttonedElement .oo-ui-buttonedElement-button > .oo-ui-indicatedElement-indicator {
+       margin-right: -0.75em;
+}
+.oo-ui-buttonedElement.oo-ui-widget-disabled .oo-ui-buttonedElement-button {
+       cursor: default;
+}
+
+.oo-ui-buttonedElement-frameless {
+       display: inline-block;
+       position: relative;
+       -webkit-transition: opacity 200ms;
+       -moz-transition: opacity 200ms;
+       -o-transition: opacity 200ms;
+       transition: opacity 200ms;
+}
+
+.oo-ui-buttonedElement-frameless .oo-ui-buttonedElement-button:hover > .oo-ui-iconedElement-icon,
+.oo-ui-buttonedElement-frameless .oo-ui-buttonedElement-button:focus > .oo-ui-iconedElement-icon {
+       opacity: 1;
+}
+
+.oo-ui-buttonedElement-frameless.oo-ui-widget-disabled .oo-ui-buttonedElement-button > .oo-ui-iconedElement-icon {
+       opacity: 0.2;
+}
+
+.oo-ui-buttonedElement-frameless .oo-ui-buttonedElement-button > .oo-ui-labeledElement-label {
+       display: inline-block;
+       vertical-align: middle;
+       margin-left: 0.25em;
+       color: #333;
+}
+
+.oo-ui-buttonedElement-frameless .oo-ui-buttonedElement-button:hover > .oo-ui-labeledElement-label,
+.oo-ui-buttonedElement-frameless .oo-ui-buttonedElement-button:focus > .oo-ui-labeledElement-label {
+       color: #000;
+}
+
+.oo-ui-buttonedElement-frameless.oo-ui-widget-disabled .oo-ui-buttonedElement-button > .oo-ui-labeledElement-label {
+       color: #ccc;
+}
+
+/* OO.ui.ButtonWidget */
+
+.oo-ui-buttonedElement-framed .oo-ui-buttonedElement-button {
+       display: inline-block;
+       font-size: 1em;
+       margin: 0.1em 0;
+       padding: 0.2em 0.8em;
+       border-radius: 0.3em;
+       vertical-align: top;
+       text-shadow: 0 1px 1px rgba(255, 255, 255, 0.5);
+       text-align: center;
+
+       /* Animation */
+       -webkit-transition: border-color 100ms;
+       -moz-transition: border-color 100ms;
+       -o-transition: border-color 100ms;
+       transition: border-color 100ms;
+
+       /* Gray */
+       border: 1px #c9c9c9 solid;
+       background-color: #dddddd;
+       filter: progid:DXImageTransform.Microsoft.gradient(
+               GradientType=0,startColorstr=#ffffff, endColorstr=#dddddd
+       );
+       background-image: -webkit-gradient(
+               linear, right top, right bottom, color-stop(0%,#ffffff), color-stop(100%,#dddddd)
+       );
+       background-image: -webkit-linear-gradient(top, #ffffff 0%, #dddddd 100%);
+       background-image: -moz-linear-gradient(top, #ffffff 0%, #dddddd 100%);
+       background-image: -ms-linear-gradient(top, #ffffff 0%, #dddddd 100%);
+       background-image: -o-linear-gradient(top, #ffffff 0%, #dddddd 100%);
+       background-image: linear-gradient(top, #ffffff 0%, #dddddd 100%);
+}
+
+.oo-ui-buttonedElement-framed .oo-ui-buttonedElement-button:hover,
+.oo-ui-buttonedElement-framed .oo-ui-buttonedElement-button:focus {
+       border-color: #aaa;
+}
+
+.oo-ui-buttonedElement-framed .oo-ui-buttonedElement-button:active,
+.oo-ui-buttonedElement-framed.oo-ui-buttonedElement-active .oo-ui-buttonedElement-button {
+       box-shadow: inset 0 1px 4px 0 rgba(0, 0, 0, 0.07);
+       color: black;
+
+       /* Gray */
+       border-color: #c9c9c9;
+       background-color: #dddddd;
+       filter: progid:DXImageTransform.Microsoft.gradient(
+               GradientType=0,startColorstr=#dddddd, endColorstr=#ffffff
+       );
+       background-image: -webkit-gradient(
+               linear, right top, right bottom, color-stop(0%,#dddddd), color-stop(100%,#ffffff)
+       );
+       background-image: -webkit-linear-gradient(top, #dddddd 0%, #ffffff 100%);
+       background-image: -moz-linear-gradient(top, #dddddd 0%, #ffffff 100%);
+       background-image: -ms-linear-gradient(top, #dddddd 0%, #ffffff 100%);
+       background-image: -o-linear-gradient(top, #dddddd 0%, #ffffff 100%);
+       background-image: linear-gradient(top, #dddddd 0%, #ffffff 100%);
+}
+
+.oo-ui-buttonedElement-framed.oo-ui-iconedElement .oo-ui-buttonedElement-button > .oo-ui-iconedElement-icon {
+       margin-left: -0.5em;
+       margin-right: -0.5em;
+}
+
+.oo-ui-buttonedElement-framed.oo-ui-iconedElement.oo-ui-labeledElement .oo-ui-buttonedElement-button > .oo-ui-iconedElement-icon {
+       margin-left: -0.5em;
+       margin-right: 0;
+}
+
+.oo-ui-buttonedElement-framed .oo-ui-buttonedElement-button > .oo-ui-labeledElement-label {
+       display: inline-block;
+       vertical-align: middle;
+       line-height: 1.9em;
+}
+
+.oo-ui-buttonedElement-framed.oo-ui-flaggableElement-destructive .oo-ui-buttonedElement-button {
+       /* Red text */
+       color: #d45353;
+}
+
+.oo-ui-buttonedElement-framed.oo-ui-flaggableElement-constructive .oo-ui-buttonedElement-button {
+       /* Green */
+       border: solid 1px #b8d892;
+       background-color: #f0fbe1;
+       filter: progid:DXImageTransform.Microsoft.gradient(
+               GradientType=0,startColorstr=#f0fbe1, endColorstr=#c3e59a
+       );
+       background-image: -webkit-gradient(
+               linear, right top, right bottom, color-stop(0%,#f0fbe1), color-stop(100%,#c3e59a)
+       );
+       background-image: -webkit-linear-gradient(top, #f0fbe1 0%, #c3e59a 100%);
+       background-image: -moz-linear-gradient(top, #f0fbe1 0%, #c3e59a 100%);
+       background-image: -ms-linear-gradient(top, #f0fbe1 0%, #c3e59a 100%);
+       background-image: -o-linear-gradient(top, #f0fbe1 0%, #c3e59a 100%);
+       background-image: linear-gradient(top, #f0fbe1 0%, #c3e59a 100%);
+}
+
+.oo-ui-buttonedElement-framed.oo-ui-flaggableElement-constructive .oo-ui-buttonedElement-button:hover,
+.oo-ui-buttonedElement-framed.oo-ui-flaggableElement-constructive .oo-ui-buttonedElement-button:focus {
+       border-color: #adcb89;
+}
+
+.oo-ui-buttonedElement-framed.oo-ui-flaggableElement-constructive .oo-ui-buttonedElement-button:active,
+.oo-ui-buttonedElement-framed.oo-ui-buttonedElement-active.oo-ui-flaggableElement-constructive .oo-ui-buttonedElement-button {
+       /* Green */
+       border: solid 1px #b8d892;
+       background-color: #c3e59a;
+       filter: progid:DXImageTransform.Microsoft.gradient(
+               GradientType=0,startColorstr=#c3e59a, endColorstr=#f0fbe1
+       );
+       background-image: -webkit-gradient(
+               linear, right top, right bottom, color-stop(0%,#c3e59a), color-stop(100%,#f0fbe1)
+       );
+       background-image: -webkit-linear-gradient(top, #c3e59a 0%, #f0fbe1 100%);
+       background-image: -moz-linear-gradient(top, #c3e59a 0%, #f0fbe1 100%);
+       background-image: -ms-linear-gradient(top, #c3e59a 0%, #f0fbe1 100%);
+       background-image: -o-linear-gradient(top, #c3e59a 0%, #f0fbe1 100%);
+       background-image: linear-gradient(top, #c3e59a 0%, #f0fbe1 100%);
+}
+
+.oo-ui-buttonedElement-framed.oo-ui-flaggableElement-primary .oo-ui-buttonedElement-button {
+       /* Blue */
+       border: solid 1px #a6cee1;
+       background-color: #eaf4fa;
+       filter: progid:DXImageTransform.Microsoft.gradient(
+               GradientType=0,startColorstr=#eaf4fa, endColorstr=#b0d9ee
+       );
+       background-image: -webkit-gradient(
+               linear, right top, right bottom, color-stop(0%,#eaf4fa), color-stop(100%,#b0d9ee)
+       );
+       background-image: -webkit-linear-gradient(top, #eaf4fa 0%, #b0d9ee 100%);
+       background-image: -moz-linear-gradient(top, #eaf4fa 0%, #b0d9ee 100%);
+       background-image: -ms-linear-gradient(top, #eaf4fa 0%, #b0d9ee 100%);
+       background-image: -o-linear-gradient(top, #eaf4fa 0%, #b0d9ee 100%);
+       background-image: linear-gradient(top, #eaf4fa 0%, #b0d9ee 100%);
+}
+
+.oo-ui-buttonedElement-framed.oo-ui-flaggableElement-primary .oo-ui-buttonedElement-button:hover,
+.oo-ui-buttonedElement-framed.oo-ui-flaggableElement-primary .oo-ui-buttonedElement-button:focus {
+       border-color: #9dc2d4;
+}
+
+.oo-ui-buttonedElement-framed.oo-ui-flaggableElement-primary .oo-ui-buttonedElement-button:active,
+.oo-ui-buttonedElement-framed.oo-ui-buttonedElement-active.oo-ui-flaggableElement-primary .oo-ui-buttonedElement-button {
+       /* Blue */
+       border: solid 1px #a6cee1;
+       background-color: #b0d9ee;
+       filter: progid:DXImageTransform.Microsoft.gradient(
+               GradientType=0,startColorstr=#b0d9ee, endColorstr=#eaf4fa
+       );
+       background-image: -webkit-gradient(
+               linear, right top, right bottom, color-stop(0%,#b0d9ee), color-stop(100%,#eaf4fa)
+       );
+       background-image: -webkit-linear-gradient(top, #b0d9ee 0%, #eaf4fa 100%);
+       background-image: -moz-linear-gradient(top, #b0d9ee 0%, #eaf4fa 100%);
+       background-image: -ms-linear-gradient(top, #b0d9ee 0%, #eaf4fa 100%);
+       background-image: -o-linear-gradient(top, #b0d9ee 0%, #eaf4fa 100%);
+       background-image: linear-gradient(top, #b0d9ee 0%, #eaf4fa 100%);
+}
+
+.oo-ui-buttonedElement-framed.oo-ui-widget-disabled .oo-ui-buttonedElement-button,
+.oo-ui-buttonedElement-framed.oo-ui-widget-disabled .oo-ui-buttonedElement-button:active,
+.oo-ui-buttonedElement-framed.oo-ui-buttonedElement-active.oo-ui-widget-disabled .oo-ui-buttonedElement-button:active {
+       opacity: 0.5;
+       cursor: default;
+       box-shadow: none;
+       color: #333;
+       background: #eee;
+}
+
+.oo-ui-buttonedElement-framed.oo-ui-widget-disabled .oo-ui-buttonedElement-button:hover,
+.oo-ui-buttonedElement-framed.oo-ui-widget-disabled .oo-ui-buttonedElement-button:focus {
+       border-color: #ccc;
+       box-shadow: none;
+}
+
+/* OO.ui.LabeledElement */
+
+.oo-ui-labeledElement-label {
+       display: block;
+}
+
+.oo-ui-clippableElement-clippable {
+       -webkit-box-sizing: border-box;
+       -moz-box-sizing: border-box;
+       box-sizing: border-box;
+}
+.oo-ui-frame {
+       margin: 0;
+       padding: 0;
+}
+
+.oo-ui-frame-body {
+       margin: 0;
+       padding: 0;
+       background: none;
+}
+
+.oo-ui-frame-content {
+       font-family: sans-serif;
+       font-size: 0.8em;
+}
+/* OO.ui.GridLayout */
+/* OO.ui.PanelLayout */
+
+.oo-ui-gridLayout,
+.oo-ui-panelLayout {
+       position: absolute;
+       top: 0;
+       left: 0;
+       right: 0;
+       bottom: 0;
+}
+
+.oo-ui-panelLayout-scrollable {
+       overflow-y: auto;
+}
+
+.oo-ui-panelLayout-padded {
+       padding: 2em;
+}
+
+/* OO.ui.FieldsetLayout */
+
+.oo-ui-fieldsetLayout {
+       border: none;
+       margin: 0;
+       padding: 0;
+}
+
+.oo-ui-fieldsetLayout + .oo-ui-fieldsetLayout {
+       margin-top: 2em;
+}
+
+.oo-ui-fieldsetLayout-labeled {
+       margin-top: -0.75em;
+}
+
+.oo-ui-fieldsetLayout > legend.oo-ui-labeledElement-label {
+       font-size: 1.5em;
+       margin-bottom: 0.5em;
+}
+
+.oo-ui-fieldsetLayout-decorated > legend.oo-ui-labeledElement-label {
+       padding-left: 1.75em;
+       background-position: left center;
+       background-repeat: no-repeat;
+}
+
+/* OO.ui.BookletLayout */
+
+.oo-ui-bookletLayout-stackLayout .oo-ui-panelLayout {
+       padding: 1.5em;
+       width: 100%;
+       -webkit-box-sizing: border-box;
+       -moz-box-sizing: border-box;
+       box-sizing: border-box;
+}
+
+.oo-ui-bookletLayout-stackLayout .oo-ui-panelLayout-scrollable {
+       overflow-y: auto;
+}
+
+.oo-ui-bookletLayout-stackLayout .oo-ui-panelLayout-padded {
+       padding: 2em;
+}
+
+.oo-ui-bookletLayout-outlinePanel {
+       border-right: solid 1px #ddd;
+}
+
+.oo-ui-bookletLayout-outlinePanel-editable .oo-ui-outlineWidget {
+       position: absolute;
+       top: 0;
+       left: 0;
+       right: 0;
+       bottom: 3em;
+       overflow-y: auto;
+}
+
+.oo-ui-bookletLayout-outlinePanel .oo-ui-outlineControlsWidget {
+       position: absolute;
+       bottom: 0;
+       left: 0;
+       right: 0;
+       box-shadow: 0 0 0.25em rgba(0,0,0,0.25);
+}
+
+.oo-ui-stackLayout > .oo-ui-panelLayout {
+       display: none;
+}
+
+.oo-ui-stackLayout-continuous > .oo-ui-panelLayout {
+       display: block;
+       position: relative;
+       margin-bottom: 1em;
+       box-shadow: 0 0 0.5em rgba(0,0,0,0.25);
+}
+
+.oo-ui-stackLayout-continuous > .oo-ui-panelLayout:last-child {
+       margin-bottom: 0;
+}
+/* OO.ui.PopupTool */
+
+.oo-ui-popupTool .oo-ui-popupWidget {
+       margin-left: 1.25em;
+       font-size: 0.8em;
+}
+
+.oo-ui-popupTool .oo-ui-popupWidget-popup,
+.oo-ui-popupTool .oo-ui-popupWidget-tail {
+       z-index: 4;
+}
+.oo-ui-toolbar {
+       clear: both;
+}
+
+.oo-ui-toolbar-bar {
+       border-bottom: solid 1px #ccc;
+       background-color: white;
+       /* @embed */
+       background-image: url(images/fade-up.png);
+       background-position: left bottom;
+       background-repeat: repeat-x;
+       padding-bottom: 1px;
+       line-height: 1em;
+}
+
+.oo-ui-toolbar-bar .oo-ui-toolbar-bar {
+       border: none;
+       background: none;
+}
+
+.oo-ui-toolbar-bottom .oo-ui-toolbar-bar {
+       position: absolute;
+}
+
+.oo-ui-toolbar-actions {
+       float: right;
+}
+
+.oo-ui-toolbar-tools {
+       float: left;
+}
+
+.oo-ui-toolbar-tools,
+.oo-ui-toolbar-actions,
+.oo-ui-toolbar-shadow {
+       -webkit-user-select: none;
+       -moz-user-select: none;
+       -ms-user-select: none;
+       -o-user-select: none;
+       user-select: none;
+}
+
+.oo-ui-toolbar-actions .oo-ui-popupWidget {
+       -webkit-touch-callout: default;
+       -webkit-user-select: all;
+       -moz-user-select: all;
+       -ms-user-select: all;
+       user-select: all;
+}
+
+.oo-ui-toolbar-shadow {
+       /* @embed */
+       background-image: url(images/toolbar-shadow.png);
+       background-position: left top;
+       background-repeat: repeat-x;
+       position: absolute;
+       bottom: -9px;
+       height: 9px;
+       width: 100%;
+       pointer-events: none;
+       -webkit-transition: opacity 500ms ease-in-out;
+       -moz-transition: opacity 500ms ease-in-out;
+       -o-transition: opacity 500ms ease-in-out;
+       transition: opacity 500ms ease-in-out;
+       opacity: 0.125;
+}
+/* OO.ui.ToolGroup */
+
+.oo-ui-toolGroup {
+       display: inline-block;
+       margin: 0.3em;
+       vertical-align: middle;
+       border-radius: 0.25em;
+       border: solid 1px transparent;
+       -webkit-transition: border-color 300ms;
+       -moz-transition: border-color 300ms;
+       -o-transition: border-color 300ms;
+       transition: border-color 300ms;
+}
+
+.oo-ui-toolGroup:hover {
+       border-color: rgba(0,0,0,0.1);
+}
+
+.oo-ui-toolGroup-empty {
+       display: none;
+}
+
+.oo-ui-toolGroup .oo-ui-tool-link .oo-ui-tool-title {
+       color: #000;
+}
+
+.oo-ui-toolGroup .oo-ui-tool-link .oo-ui-iconedElement-icon {
+       background-position: center center;
+       background-repeat: no-repeat;
+}
+
+/* OO.ui.BarToolGroup */
+
+.oo-ui-barToolGroup > .oo-ui-iconedElement-icon,
+.oo-ui-barToolGroup > .oo-ui-iconedElement-label {
+       display: none;
+}
+
+.oo-ui-barToolGroup .oo-ui-tool {
+       display: inline-block;
+       position: relative;
+       vertical-align: top;
+       margin: -1px 0 -1px -1px;
+       border: solid 1px transparent;
+}
+
+.oo-ui-barToolGroup .oo-ui-tool-link {
+       display: block;
+       height: 1.5em;
+       padding: 0.25em;
+       cursor: pointer;
+}
+
+.oo-ui-barToolGroup
+       .oo-ui-tool-active:not(.oo-ui-widget-disabled) +
+       .oo-ui-tool-active:not(.oo-ui-widget-disabled)
+{
+       border-left-color: rgba(0,0,0,0.1);
+}
+
+.oo-ui-barToolGroup .oo-ui-tool:first-child {
+       border-top-left-radius: 0.25em;
+       border-bottom-left-radius: 0.25em;
+}
+
+.oo-ui-barToolGroup .oo-ui-tool:last-child {
+       margin-right: -1px;
+       border-top-right-radius: 0.25em;
+       border-bottom-right-radius: 0.25em;
+}
+
+.oo-ui-barToolGroup .oo-ui-tool:hover:not(.oo-ui-widget-disabled) {
+       border-color: rgba(0,0,0,0.2);
+}
+
+.oo-ui-barToolGroup .oo-ui-tool-active:not(.oo-ui-widget-disabled) {
+       border-color: rgba(0,0,0,0.2);
+}
+
+.oo-ui-barToolGroup .oo-ui-tool-link .oo-ui-iconedElement-icon {
+       display: block;
+       height: 1.5em;
+       width: 1.5em;
+       opacity: 0.8;
+}
+
+.oo-ui-barToolGroup .oo-ui-tool-link .oo-ui-tool-title {
+       display: none;
+}
+
+.oo-ui-barToolGroup .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-link {
+       cursor: default;
+}
+
+.oo-ui-barToolGroup .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-link .oo-ui-iconedElement-icon {
+       opacity: 0.2;
+}
+
+.oo-ui-barToolGroup .oo-ui-tool:not(.oo-ui-widget-disabled) .oo-ui-tool-link .oo-ui-iconedElement-icon {
+       opacity: 0.8;
+}
+
+.oo-ui-barToolGroup .oo-ui-tool:hover:not(.oo-ui-widget-disabled) .oo-ui-tool-link .oo-ui-iconedElement-icon {
+       opacity: 1;
+}
+
+.oo-ui-barToolGroup .oo-ui-tool-title {
+       display: none;
+}
+
+/* OO.ui.PopupToolGroup */
+
+.oo-ui-popupToolGroup {
+       position: relative;
+       height: 2em;
+       min-width: 2.5em;
+}
+
+.oo-ui-popupToolGroup.oo-ui-indicatedElement.oo-ui-iconedElement {
+       min-width: 3.5em;
+}
+
+.oo-ui-popupToolGroup-handle {
+       display: block;
+       cursor: pointer;
+}
+
+.oo-ui-popupToolGroup-handle .oo-ui-indicatedElement-indicator,
+.oo-ui-popupToolGroup-handle .oo-ui-iconedElement-icon {
+       position: absolute;
+       top: 0;
+       width: 2em;
+       height: 2em;
+       background-position: center center;
+       background-repeat: no-repeat;
+       opacity: 0.8;
+}
+
+.oo-ui-popupToolGroup-handle .oo-ui-indicatedElement-indicator {
+       right: 0;
+}
+
+.oo-ui-popupToolGroup-handle .oo-ui-iconedElement-icon {
+       left: 0.25em;
+}
+
+.oo-ui-popupToolGroup-handle .oo-ui-labeledElement-label {
+       line-height: 2.6em;
+       font-size: 0.8em;
+       margin: 0 1em;
+}
+
+.oo-ui-popupToolGroup.oo-ui-iconedElement .oo-ui-popupToolGroup-handle .oo-ui-labeledElement-label {
+       margin-left: 3.25em;
+}
+
+.oo-ui-popupToolGroup.oo-ui-indicatedElement .oo-ui-popupToolGroup-handle .oo-ui-labeledElement-label {
+       margin-right: 2.25em;
+}
+
+.oo-ui-popupToolGroup .oo-ui-toolGroup-tools {
+       display: none;
+       position: absolute;
+       top: 2em;
+       left: -1px;
+       z-index: 4;
+       border: solid 1px #ccc;
+       background-color: white;
+       box-shadow: 0 0.25em 1em rgba(0,0,0,0.25);
+}
+
+.oo-ui-popupToolGroup .oo-ui-toolGroup-tools .oo-ui-iconedElement-icon {
+       background-repeat: no-repeat;
+       background-position: center center;
+}
+
+.oo-ui-popupToolGroup-active:not(.oo-ui-widget-disabled) > .oo-ui-toolGroup-tools {
+       display: block;
+}
+
+.oo-ui-popupToolGroup-active:not(.oo-ui-widget-disabled) {
+       border-bottom-left-radius: 0;
+       border-bottom-right-radius: 0;
+}
+
+.oo-ui-popupToolGroup .oo-ui-tool-link .oo-ui-iconedElement-icon {
+       display: inline-block;
+       vertical-align: middle;
+       height: 2em;
+       width: 2em;
+       margin-right: 0.5em;
+}
+
+.oo-ui-popupToolGroup .oo-ui-tool-link .oo-ui-tool-title {
+       display: inline-block;
+       vertical-align: middle;
+       line-height: 2em;
+       font-size: 0.8em;
+}
+
+.oo-ui-popupToolGroup .oo-ui-tool-accel {
+       display: none;
+}
+
+/* OO.ui.ListToolGroup */
+
+.oo-ui-listToolGroup .oo-ui-toolGroup-tools {
+       padding: 0.25em;
+}
+
+.oo-ui-listToolGroup .oo-ui-tool {
+       display: inline-block;
+       width: 100%;
+       -webkit-box-sizing: border-box;
+       -moz-box-sizing: border-box;
+       box-sizing: border-box;
+       border: solid 1px transparent;
+       margin: -1px 0;
+}
+
+.oo-ui-listToolGroup .oo-ui-tool-link {
+       display: block;
+       cursor: pointer;
+       white-space: nowrap;
+       padding-right: 0.5em;
+}
+
+.oo-ui-listToolGroup.oo-ui-popupToolGroup-active {
+       border-color: rgba(0,0,0,0.2);
+}
+
+.oo-ui-listToolGroup
+       .oo-ui-tool-active:not(.oo-ui-widget-disabled) +
+       .oo-ui-tool-active:not(.oo-ui-widget-disabled)
+{
+       border-top-color: rgba(0,0,0,0.1);
+}
+
+.oo-ui-listToolGroup .oo-ui-tool:hover:not(.oo-ui-widget-disabled) {
+       border-color: rgba(0,0,0,0.2);
+}
+
+.oo-ui-listToolGroup .oo-ui-tool-active:not(.oo-ui-widget-disabled) {
+       border-color: rgba(0,0,0,0.2);
+}
+
+.oo-ui-listToolGroup .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-link {
+       cursor: default;
+}
+
+.oo-ui-listToolGroup .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-link .oo-ui-tool-title {
+       color: #ccc;
+}
+
+.oo-ui-listToolGroup .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-link .oo-ui-iconedElement-icon {
+       opacity: 0.2;
+}
+
+.oo-ui-listToolGroup .oo-ui-tool:not(.oo-ui-widget-disabled) .oo-ui-tool-link .oo-ui-iconedElement-icon {
+       opacity: 0.8;
+}
+
+.oo-ui-listToolGroup .oo-ui-tool:hover:not(.oo-ui-widget-disabled) .oo-ui-tool-link .oo-ui-iconedElement-icon {
+       opacity: 1;
+}
+
+/* OO.ui.MenuToolGroup */
+
+.oo-ui-menuToolGroup {
+       border-color: rgba(0,0,0,0.1);
+}
+
+.oo-ui-menuToolGroup:hover {
+       border-color: rgba(0,0,0,0.2);
+}
+
+.oo-ui-menuToolGroup.oo-ui-popupToolGroup-active {
+       border-color: rgba(0,0,0,0.25);
+}
+
+.oo-ui-menuToolGroup .oo-ui-popupToolGroup-handle {
+       min-width: 8em;
+}
+
+.oo-ui-menuToolGroup .oo-ui-tool {
+       display: block;
+}
+
+.oo-ui-menuToolGroup .oo-ui-tool-link {
+       display: block;
+       cursor: pointer;
+       white-space: nowrap;
+       padding: 0.25em 1em 0.25em 0.25em;
+}
+
+.oo-ui-menuToolGroup .oo-ui-tool-link .oo-ui-iconedElement-icon {
+       background-image: none;
+}
+
+.oo-ui-menuToolGroup .oo-ui-tool-active .oo-ui-tool-link .oo-ui-iconedElement-icon {
+       /* @embed */
+       background-image: url(images/icons/check.png);
+}
+
+.oo-ui-menuToolGroup .oo-ui-tool:hover {
+       background-color: #e1f3ff;
+}
+
+/* Common */
+
+.oo-ui-barToolGroup .oo-ui-tool-active:not(.oo-ui-widget-disabled),
+.oo-ui-listToolGroup .oo-ui-tool-active:not(.oo-ui-widget-disabled),
+.oo-ui-popupToolGroup-active:not(.oo-ui-widget-disabled) {
+       /* @embed */
+       background-image: url(images/fade-down.png);
+       background-position: left top;
+       background-repeat: repeat-x;
+       box-shadow: inset 0 0.07em 0.07em 0 rgba(0, 0, 0, 0.07);
+}
+/* OO.ui.ButtonWidget */
+
+.oo-ui-buttonWidget {
+       display: inline-block;
+       vertical-align: middle;
+}
+
+/* OO.ui.PopupButtonWidget */
+
+.oo-ui-popupButtonWidget {
+       position: relative;
+}
+
+.oo-ui-popupButtonWidget .oo-ui-popupWidget {
+       position: absolute;
+       left: 1em;
+       cursor: auto;
+}
+
+/* OO.ui.ButtonGroupWidget */
+
+.oo-ui-buttonGroupWidget {
+       display: inline-block;
+       border-radius: 0.3em;
+}
+
+.oo-ui-buttonGroupWidget .oo-ui-buttonedElement-framed .oo-ui-buttonedElement-button {
+       border-radius: 0;
+       margin-bottom: -1px;
+       margin-left: -1px;
+}
+
+.oo-ui-buttonGroupWidget .oo-ui-buttonedElement-framed:first-child .oo-ui-buttonedElement-button {
+       border-bottom-left-radius: 0.3em;
+       border-top-left-radius: 0.3em;
+       margin-left: 0;
+}
+
+.oo-ui-buttonGroupWidget .oo-ui-buttonedElement-framed:last-child .oo-ui-buttonedElement-button {
+       border-bottom-right-radius: 0.3em;
+       border-top-right-radius: 0.3em;
+}
+
+/* OO.ui.SelectWidget */
+
+.oo-ui-selectWidget {
+       list-style: none;
+       margin: 0;
+       padding: 0;
+}
+
+/* OO.ui.OptionWidget */
+
+.oo-ui-optionWidget {
+       position: relative;
+       display: block;
+       border: none;
+       list-style: none;
+       margin: 0;
+       padding: 0.5em 2em 0.5em 3em;
+       cursor: pointer;
+}
+
+.oo-ui-optionWidget .oo-ui-labeledElement-label {
+       line-height: 1.5em;
+       white-space: nowrap;
+       text-overflow: ellipsis;
+       overflow: hidden;
+}
+
+.oo-ui-optionWidget-highlighted {
+       background-color: #e1f3ff;
+}
+
+.oo-ui-optionWidget-selected {
+       background-color: #a7dcff;
+}
+
+.oo-ui-optionWidget.oo-ui-widget-disabled {
+       cursor: default;
+}
+
+.oo-ui-optionWidget .oo-ui-iconedElement-icon,
+.oo-ui-optionWidget .oo-ui-indicatedElement-indicator {
+       position: absolute;
+       top: 50%;
+       width: 2em;
+       height: 2em;
+       margin-top: -1em;
+       background-repeat: no-repeat;
+       background-position: center center;
+}
+
+.oo-ui-optionWidget .oo-ui-iconedElement-icon {
+       left: 0.5em;
+}
+
+.oo-ui-optionWidget .oo-ui-indicatedElement-indicator {
+       right: 0.5em;
+}
+
+/* OO.ui.OutlineItemWidget */
+
+.oo-ui-outlineItemWidget {
+       position: relative;
+       padding: 0.75em 0.75em 0.75em 3.5em;
+       -webkit-user-select: none;
+       -moz-user-select: none;
+       -ms-user-select: none;
+       user-select: none;
+       cursor: pointer;
+       font-size: 1.1em;
+}
+
+.oo-ui-outlineItemWidget-level-1 {
+       padding-left: 5em;
+}
+
+.oo-ui-outlineItemWidget-level-2 {
+       padding-left: 6.5em;
+}
+
+.oo-ui-outlineItemWidget.oo-ui-optionWidget-selected {
+       background-color: #a7dcff;
+       text-shadow: 0 1px 1px rgba(255,255,255,0.5);
+}
+
+.oo-ui-outlineItemWidget-level-0 .oo-ui-iconedElement-icon {
+       left: 1em;
+}
+
+.oo-ui-outlineItemWidget-level-1 .oo-ui-iconedElement-icon {
+       left: 2.5em;
+}
+
+.oo-ui-outlineItemWidget-level-2 .oo-ui-iconedElement-icon {
+       left: 4em;
+}
+
+/* OO.ui.OutlineControlsWidget */
+
+.oo-ui-outlineControlsWidget {
+       height: 3em;
+       background-color: #fff;
+}
+
+.oo-ui-outlineControlsWidget-adders,
+.oo-ui-outlineControlsWidget-movers {
+       float: left;
+       -webkit-box-sizing: border-box;
+       -moz-box-sizing: border-box;
+       box-sizing: border-box;
+       height: 3em;
+       padding: 0.5em;
+}
+
+.oo-ui-outlineControlsWidget-adders {
+       float: left;
+}
+.oo-ui-outlineControlsWidget-movers {
+       float: right;
+}
+
+.oo-ui-outlineControlsWidget-adders .oo-ui-buttonWidget {
+       float: left;
+}
+
+.oo-ui-outlineControlsWidget-movers .oo-ui-buttonWidget {
+       float: right;
+}
+
+.oo-ui-outlineControlsWidget-adders .oo-ui-buttonWidget:first-child,
+.oo-ui-outlineControlsWidget-adders .oo-ui-buttonWidget:first-child:hover {
+       opacity: 0.25;
+       cursor: default;
+}
+
+/* OO.ui.InputLabelWidget */
+
+.oo-ui-inputLabelWidget {
+       padding: 0.5em 0;
+}
+
+/* OO.ui.TextInputWidget */
+
+.oo-ui-textInputWidget {
+       -webkit-box-sizing: border-box;
+       -moz-box-sizing: border-box;
+       box-sizing: border-box;
+       width: 20em;
+       position: relative;
+}
+
+.oo-ui-textInputWidget input,
+.oo-ui-textInputWidget input:focus[readonly],
+.oo-ui-widget-disabled.oo-ui-textInputWidget input:focus,
+.oo-ui-textInputWidget textarea,
+.oo-ui-textInputWidget textarea:focus[readonly],
+.oo-ui-widget-disabled.oo-ui-textInputWidget textarea:focus {
+       display: inline-block;
+       font-size: 1em;
+       font-family: sans-serif;
+       background-color: #fff;
+       border: solid 1px #ccc;
+       box-shadow: 0 0 0 white, inset 0 0.1em 0.2em #ddd;
+       padding: 0.5em;
+       border-radius: 0.25em;
+       -webkit-box-sizing: border-box;
+       -moz-box-sizing: border-box;
+       box-sizing: border-box;
+       width: 100%;
+       resize: none;
+
+       /* Animation */
+       -webkit-transition: border-color 200ms, box-shadow 200ms;
+       -moz-transition: border-color 200ms, box-shadow 200ms;
+       -o-transition: border-color 200ms, box-shadow 200ms;
+       transition: border-color 200ms, box-shadow 200ms;
+}
+
+.oo-ui-textInputWidget-pending input,
+.oo-ui-textInputWidget-pending textarea {
+       background-color: transparent;
+}
+
+.oo-ui-textInputWidget input:focus,
+.oo-ui-textInputWidget textarea:focus {
+       outline: none;
+       border-color: #a7dcff;
+       box-shadow: 0 0 0.3em #a7dcff, 0 0 0 white;
+}
+
+.oo-ui-textInputWidget input[readonly],
+.oo-ui-textInputWidget textarea[readonly] {
+       color: #777;
+       text-shadow: 0 1px 1px #fff;
+}
+
+.oo-ui-widget-disabled.oo-ui-textInputWidget input,
+.oo-ui-widget-disabled.oo-ui-textInputWidget input:focus,
+.oo-ui-widget-disabled.oo-ui-textInputWidget textarea,
+.oo-ui-widget-disabled.oo-ui-textInputWidget textarea:focus {
+       color: #ccc;
+       border-color: #ddd;
+       text-shadow: 0 1px 1px #fff;
+}
+
+.oo-ui-textInputWidget-decorated input,
+.oo-ui-textInputWidget-decorated textarea {
+       padding-left: 2em;
+}
+
+.oo-ui-textInputWidget-icon {
+       position: absolute;
+       top: 0;
+       left: 0;
+       width: 2em;
+       height: 100%;
+       background-position: right center;
+       background-repeat: no-repeat;
+}
+
+/* OO.ui.CheckboxWidget */
+.oo-ui-checkboxWidget .oo-ui-labeledElement-label {
+       display: inline-block;
+       vertical-align: middle;
+       padding-left: 0.5em;
+}
+
+.oo-ui-checkboxWidget input {
+       vertical-align: middle;
+}
+
+.oo-ui-checkboxWidget.oo-ui-widget-disabled .oo-ui-labeledElement-label {
+       opacity: 0.5;
+}
+
+/* OO.ui.MenuWidget */
+
+.oo-ui-menuWidget {
+       position: absolute;
+       background: #fff;
+       margin-top: -1px;
+       border: solid 1px #ccc;
+       border-radius: 0 0 0.25em 0.25em;
+       box-shadow: 0 0.15em 1em 0 rgba(0, 0, 0, 0.2);
+}
+
+.oo-ui-menuWidget input {
+       position: absolute;
+       width: 0;
+       height: 0;
+       overflow: hidden;
+       opacity: 0;
+}
+
+/* OO.ui.MenuItemWidget */
+
+.oo-ui-menuItemWidget {
+       position: relative;
+}
+
+.oo-ui-menuItemWidget .oo-ui-iconedElement-icon {
+       display: none;
+}
+
+.oo-ui-menuItemWidget.oo-ui-optionWidget-selected .oo-ui-iconedElement-icon {
+       display: block;
+}
+
+.oo-ui-menuItemWidget.oo-ui-optionWidget-selected {
+       background-color: transparent;
+}
+
+.oo-ui-menuItemWidget.oo-ui-optionWidget-highlighted {
+       background-color: #e1f3ff;
+}
+
+/* OO.ui.MenuSectionItemWidget */
+
+.oo-ui-menuSectionItemWidget {
+       padding: 0.33em 0.75em;
+       color: #888;
+       cursor: default;
+}
+
+/* OO.ui.ButtonSelectWidget */
+
+.oo-ui-buttonSelectWidget {
+       display: inline-block;
+       border-radius: 0.3em;
+}
+
+.oo-ui-buttonSelectWidget .oo-ui-buttonOptionWidget .oo-ui-buttonedElement-button {
+       border-radius: 0;
+       margin-left: -1px;
+}
+
+.oo-ui-buttonSelectWidget .oo-ui-buttonOptionWidget:first-child .oo-ui-buttonedElement-button {
+       border-bottom-left-radius: 0.3em;
+       border-top-left-radius: 0.3em;
+       margin-left: 0;
+}
+
+.oo-ui-buttonSelectWidget .oo-ui-buttonOptionWidget:last-child .oo-ui-buttonedElement-button {
+       border-bottom-right-radius: 0.3em;
+       border-top-right-radius: 0.3em;
+}
+
+/* OO.ui.ButtonOptionWidget */
+
+.oo-ui-buttonOptionWidget {
+       display: inline-block;
+       padding: 0;
+       background-color: transparent;
+}
+
+.oo-ui-buttonOptionWidget .oo-ui-buttonedElement-button {
+       position: relative;
+       height: 1.9em;
+}
+
+.oo-ui-buttonOptionWidget.oo-ui-iconedElement .oo-ui-iconedElement-icon,
+.oo-ui-buttonOptionWidget.oo-ui-indicatedElement .oo-ui-indicatedElement-indicator {
+       position: static;
+       display: inline-block;
+       vertical-align: middle;
+       height: 1.9em;
+       margin-top: 0;
+}
+
+/* OO.ui.PopupWidget */
+
+.oo-ui-popupWidget-popup {
+       position: absolute;
+       overflow: hidden;
+       border: solid 1px #ccc;
+       border-radius: 0.25em;
+       background-color: #fff;
+       box-shadow: 0 0.15em 0.5em 0 rgba(0, 0, 0, 0.2);
+}
+
+.oo-ui-popupWidget-tail {
+       display: none;
+}
+
+.oo-ui-popupWidget-tailed .oo-ui-popupWidget-popup {
+       margin-top: 7px;
+}
+
+.oo-ui-popupWidget-tailed .oo-ui-popupWidget-tail {
+       display: block;
+       position: absolute;
+       /* @embed */
+       background-image: url(images/tail.svg);
+       background-repeat: no-repeat;
+       width: 15px;
+       height: 8px;
+       margin-left: -7px;
+}
+
+.oo-ui-popupWidget-transitioning .oo-ui-popupWidget-popup {
+       -webkit-transition: width 100ms, height 100ms, left 100ms;
+       -moz-transition: width 100ms, height 100ms, left 100ms;
+       -o-transition: width 100ms, height 100ms, left 100ms;
+       transition: width 100ms, height 100ms, left 100ms;
+       -webkit-transition-timing-function: ease-in-out;
+       -moz-transition-timing-function: ease-in-out;
+       -o-transition-timing-function: ease-in-out;
+       transition-timing-function: ease-in-out;
+}
+
+.oo-ui-popupWidget-head {
+       height: 2.5em;
+       -webkit-touch-callout: none;
+       -webkit-user-select: none;
+       -moz-user-select: none;
+       -ms-user-select: none;
+       user-select: none;
+}
+
+.oo-ui-popupWidget-head .oo-ui-buttonWidget {
+       float: right;
+       margin: 0.25em;
+}
+
+.oo-ui-popupWidget-head .oo-ui-labeledElement-label {
+       float: left;
+       margin: 0.75em 1em;
+       cursor: default;
+}
+
+.oo-ui-popupWidget-body {
+       box-shadow: 0 0 0.66em rgba(0,0,0,0.25);
+}
+
+/* OO.ui.SearchWidget */
+
+.oo-ui-searchWidget-query {
+       position: absolute;
+       top: 0;
+       left: 0;
+       right: 0;
+       height: 4em;
+       padding: 0 1em;
+       box-shadow: 0 0 0.5em rgba(0,0,0,0.2);
+}
+
+.oo-ui-searchWidget-query .oo-ui-textInputWidget {
+       width: 100%;
+       margin: 0.75em 0;
+}
+
+.oo-ui-searchWidget-results {
+       position: absolute;
+       top: 4em;
+       bottom: 0;
+       left: 0;
+       right: 0;
+       padding: 1em;
+       overflow-x: hidden;
+       overflow-y: auto;
+       line-height: 0;
+}
+
+/* OO.ui.ToggleSwitchWidget */
+
+.oo-ui-toggleSwitchWidget {
+       position: relative;
+       display: inline-block;
+       vertical-align: middle;
+       height: 2em;
+       width: 3em;
+       border-radius: 1em;
+       overflow: hidden;
+       box-shadow: 0 0 0 white, inset 0 0.1em 0.2em #ddd;
+       border: solid 1px #ccc;
+       cursor: pointer;
+       -webkit-box-sizing: border-box;
+       -moz-box-sizing: border-box;
+       box-sizing: border-box;
+       -webkit-transform: translateZ(0px);
+       -moz-transform: translateZ(0px);
+       -ms-transform: translateZ(0px);
+       -o-transform: translateZ(0px);
+       transform: translateZ(0px);
+
+       /* Gray */
+       background-color: #dddddd;
+       filter: progid:DXImageTransform.Microsoft.gradient(
+               GradientType=0,startColorstr=#dddddd, endColorstr=#ffffff
+       );
+       background-image: -webkit-gradient(
+               linear, right top, right bottom, color-stop(0%,#dddddd), color-stop(100%,#ffffff)
+       );
+       background-image: -webkit-linear-gradient(top, #dddddd 0%, #ffffff 100%);
+       background-image: -moz-linear-gradient(top, #dddddd 0%, #ffffff 100%);
+       background-image: -ms-linear-gradient(top, #dddddd 0%, #ffffff 100%);
+       background-image: -o-linear-gradient(top, #dddddd 0%, #ffffff 100%);
+       background-image: linear-gradient(top, #dddddd 0%, #ffffff 100%);
+}
+
+.oo-ui-toggleSwitchWidget.oo-ui-widget-disabled {
+       opacity: 0.5;
+       cursor: default;
+}
+
+.oo-ui-toggleSwitchWidget-grip {
+       -webkit-transition: left 200ms ease-in-out, margin-left 200ms ease-in-out;
+       -moz-transition: left 200ms ease-in-out, margin-left 200ms ease-in-out;
+       -o-transition: left 200ms ease-in-out, margin-left 200ms ease-in-out;
+       transition: left 200ms ease-in-out, margin-left 200ms ease-in-out;
+}
+
+.oo-ui-toggleSwitchWidget-grip {
+       position: absolute;
+       display: block;
+       top: 0.25em;
+       left: 0.25em;
+       width: 1.5em;
+       height: 1.5em;
+       border-radius: 1em;
+       box-shadow: 0 0.1em 0.25em rgba(0, 0, 0, 0.1);
+       -webkit-box-sizing: border-box;
+       -moz-box-sizing: border-box;
+       box-sizing: border-box;
+
+       /* Gray */
+       border: 1px #c9c9c9 solid;
+       background-color: #ffffff;
+       filter: progid:DXImageTransform.Microsoft.gradient(
+               GradientType=0,startColorstr=#ffffff, endColorstr=#dddddd
+       );
+       background-image: -webkit-gradient(
+               linear, right top, right bottom, color-stop(0%,#ffffff), color-stop(100%,#dddddd)
+       );
+       background-image: -webkit-linear-gradient(top, #ffffff 0%, #dddddd 100%);
+       background-image: -moz-linear-gradient(top, #ffffff 0%, #dddddd 100%);
+       background-image: -ms-linear-gradient(top, #ffffff 0%, #dddddd 100%);
+       background-image: -o-linear-gradient(top, #ffffff 0%, #dddddd 100%);
+       background-image: linear-gradient(top, #ffffff 0%, #dddddd 100%);
+}
+
+.oo-ui-toggleSwitchWidget:not(.oo-ui-widget-disabled):hover,
+.oo-ui-toggleSwitchWidget:not(.oo-ui-widget-disabled):hover .oo-ui-toggleSwitchWidget-grip {
+       border-color: #aaa;
+}
+
+.oo-ui-toggleWidget-on .oo-ui-toggleSwitchWidget-grip {
+       left: 1.25em;
+       margin-left: -2px;
+}
+
+.oo-ui-toggleWidget-off .oo-ui-toggleSwitchWidget-grip {
+       left: 0.25em;
+       margin-left: 0;
+}
+
+.oo-ui-toggleSwitchWidget .oo-ui-toggleSwitchWidget-on {
+       position: absolute;
+       top: 0;
+       bottom: 0;
+       right: 0;
+       left: 0;
+       border-radius: 1em;
+       box-shadow: inset 0 1px 4px 0 rgba(0, 0, 0, 0.07);
+       -webkit-touch-callout: none;
+       -webkit-user-select: none;
+       -moz-user-select: none;
+       -ms-user-select: none;
+       user-select: none;
+
+       -webkit-transition: opacity 200ms ease-in-out;
+       -moz-transition: opacity 200ms ease-in-out;
+       -o-transition: opacity 200ms ease-in-out;
+       transition: opacity 200ms ease-in-out;
+
+       /* Blue */
+       background-color: #eaf4fa;
+       filter: progid:DXImageTransform.Microsoft.gradient(
+               GradientType=0,startColorstr=#b0d9ee, endColorstr=#eaf4fa
+       );
+       background-image: -webkit-gradient(
+               linear, right top, right bottom, color-stop(0%,#b0d9ee), color-stop(100%,#eaf4fa)
+       );
+       background-image: -webkit-linear-gradient(top, #b0d9ee 0%, #eaf4fa 100%);
+       background-image: -moz-linear-gradient(top, #b0d9ee 0%, #eaf4fa 100%);
+       background-image: -ms-linear-gradient(top, #b0d9ee 0%, #eaf4fa 100%);
+       background-image: -o-linear-gradient(top, #b0d9ee 0%, #eaf4fa 100%);
+       background-image: linear-gradient(top, #b0d9ee 0%, #eaf4fa 100%);
+}
+
+.oo-ui-toggleWidget-on .oo-ui-toggleSwitchWidget-on {
+       opacity: 1;
+}
+
+.oo-ui-toggleWidget-off .oo-ui-toggleSwitchWidget-on {
+       opacity: 0;
+}
+.oo-ui-window-head {
+       -webkit-touch-callout: none;
+       -webkit-user-select: none;
+       -moz-user-select: none;
+       -ms-user-select: none;
+       user-select: none;
+}
+
+.oo-ui-window-body {
+       padding: 0 0.75em;
+}
+
+.oo-ui-window-icon {
+       float: left;
+       width: 2em;
+       height: 2em;
+       line-height: 2em;
+       margin-right: 0.5em;
+       background-position: right center;
+       background-repeat: no-repeat;
+}
+
+.oo-ui-window-title {
+       float: left;
+       line-height: 2em;
+       color: #333;
+       white-space: nowrap;
+       cursor: default;
+}
+
+.oo-ui-window-overlay {
+       font-family: sans-serif;
+       line-height: 1.5em;
+       font-size: 1em;
+       position: absolute;
+       top: 0;
+       left: 0;
+}
+/* Icons */
+
+.oo-ui-icon-add-item {
+       /* @embed */
+       background-image: url(images/icons/add-item.svg);
+}
+
+.oo-ui-icon-advanced {
+       /* @embed */
+       background-image: url(images/icons/advanced.svg);
+}
+
+.oo-ui-icon-alert {
+       /* @embed */
+       background-image: url(images/icons/alert.svg);
+}
+
+.oo-ui-icon-check {
+       /* @embed */
+       background-image: url(images/icons/check.svg);
+}
+
+.oo-ui-icon-clear {
+       /* @embed */
+       background-image: url(images/icons/clear.svg);
+}
+
+.oo-ui-icon-close {
+       /* @embed */
+       background-image: url(images/icons/close.svg);
+}
+
+.oo-ui-icon-code {
+       /* @embed */
+       background-image: url(images/icons/code.svg);
+}
+
+.oo-ui-icon-collapse {
+       /* @embed */
+       background-image: url(images/icons/collapse.svg);
+}
+
+.oo-ui-icon-comment {
+       /* @embed */
+       background-image: url(images/icons/comment.svg);
+}
+
+.oo-ui-icon-expand {
+       /* @embed */
+       background-image: url(images/icons/expand.svg);
+}
+
+.oo-ui-icon-help {
+       /* @embed */
+       background-image: url(images/icons/help.svg);
+}
+
+.oo-ui-icon-link {
+       /* @embed */
+       background-image: url(images/icons/link.svg);
+}
+
+.oo-ui-icon-menu {
+       /* @embed */
+       background-image: url(images/icons/menu.svg);
+}
+
+.oo-ui-icon-next {
+       /* @embed */
+       background-image: url(images/icons/move-ltr.svg);
+}
+
+.oo-ui-icon-picture {
+       /* @embed */
+       background-image: url(images/icons/picture.svg);
+}
+
+.oo-ui-icon-previous {
+       /* @embed */
+       background-image: url(images/icons/move-rtl.svg);
+}
+
+.oo-ui-icon-redo {
+       /* @embed */
+       background-image: url(images/icons/arched-arrow-ltr.svg);
+}
+
+.oo-ui-icon-remove {
+       /* @embed */
+       background-image: url(images/icons/remove.svg);
+}
+
+.oo-ui-icon-search {
+       /* @embed */
+       background-image: url(images/icons/search.svg);
+}
+
+.oo-ui-icon-settings {
+       /* @embed */
+       background-image: url(images/icons/settings.svg);
+}
+
+.oo-ui-icon-tag {
+       /* @embed */
+       background-image: url(images/icons/tag.svg);
+}
+
+.oo-ui-icon-undo {
+       /* @embed */
+       background-image: url(images/icons/arched-arrow-rtl.svg);
+}
+
+.oo-ui-icon-window {
+       /* @embed */
+       background-image: url(images/icons/window.svg);
+}
+
+/* Indicators */
+
+.oo-ui-indicator-down {
+       /* @embed */
+       background-image: url(images/indicators/down.svg);
+}
+
+.oo-ui-indicator-required {
+       /* @embed */
+       background-image: url(images/indicators/required.svg);
+}
+
+.oo-ui-indicator-up {
+       /* @embed */
+       background-image: url(images/indicators/up.svg);
+}
diff --git a/resources/oojs/.gitignore b/resources/oojs/.gitignore
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/resources/oojs/i18n/ace.json b/resources/oojs/i18n/ace.json
deleted file mode 100644 (file)
index 554ae57..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Si Gam Acèh"
-        ]
-    },
-    "ooui-dialog-action-close": "Tôp",
-    "ooui-outline-control-move-down": "Pinah item u yup",
-    "ooui-outline-control-move-up": "Pinah item u ateuëh",
-    "ooui-toolbar-more": "Lom"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/af.json b/resources/oojs/i18n/af.json
deleted file mode 100644 (file)
index a622f89..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Naudefj"
-        ]
-    },
-    "ooui-dialog-action-close": "Sluit",
-    "ooui-outline-control-move-down": "Skuif item af",
-    "ooui-outline-control-move-up": "Skuif item op"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/am.json b/resources/oojs/i18n/am.json
deleted file mode 100644 (file)
index 61e4ff6..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Elfalem"
-        ]
-    },
-    "ooui-dialog-action-close": "ለመዝጋት"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/ar.json b/resources/oojs/i18n/ar.json
deleted file mode 100644 (file)
index 65e1364..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Ciphers",
-            "Claw eg",
-            "Elfalem",
-            "Jdforrester",
-            "Mido",
-            "OsamaK",
-            "زكريا",
-            "مشعل الحربي"
-        ]
-    },
-    "ooui-dialog-action-close": "أغلق",
-    "ooui-outline-control-move-down": "انقل العنصر للأسفل",
-    "ooui-outline-control-move-up": "انقل العنصر للأعلى",
-    "ooui-toolbar-more": "مزيد"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/arc.json b/resources/oojs/i18n/arc.json
deleted file mode 100644 (file)
index 0f9e75d..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Basharh"
-        ]
-    },
-    "ooui-dialog-action-close": "ܣܟܘܪ"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/ast.json b/resources/oojs/i18n/ast.json
deleted file mode 100644 (file)
index 959ea23..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Basharh",
-            "Bishnu Saikia",
-            "Xuacu"
-        ]
-    },
-    "ooui-dialog-action-close": "Zarrar",
-    "ooui-outline-control-move-down": "Mover abaxo l'elementu",
-    "ooui-outline-control-move-up": "Mover arriba l'elementu",
-    "ooui-toolbar-more": "Más"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/az.json b/resources/oojs/i18n/az.json
deleted file mode 100644 (file)
index 8bfcf88..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Cekli829",
-            "Interfase",
-            "Jduranboger"
-        ]
-    },
-    "ooui-dialog-action-close": "Bağla",
-    "ooui-outline-control-move-down": "Bəndi aşağı apar",
-    "ooui-outline-control-move-up": "Bəndi yuxarı apar"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/ba.json b/resources/oojs/i18n/ba.json
deleted file mode 100644 (file)
index 4af0114..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "AiseluRB",
-            "Amire80",
-            "Assele",
-            "Haqmar",
-            "Sagan",
-            "Рустам Нурыев"
-        ]
-    },
-    "ooui-dialog-action-close": "Ябырға",
-    "ooui-outline-control-move-down": "Аҫҡа күсерергә",
-    "ooui-outline-control-move-up": "Өҫкә күсерергә"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/bcl.json b/resources/oojs/i18n/bcl.json
deleted file mode 100644 (file)
index aff451e..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Geopoet",
-            "Sky Harbor"
-        ]
-    },
-    "ooui-dialog-action-close": "Seraduhon",
-    "ooui-outline-control-move-down": "Balyuhon an aytem paibaba",
-    "ooui-outline-control-move-up": "Balyuhon an aytem paitaas",
-    "ooui-toolbar-more": "Kadugangan"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/be-tarask.json b/resources/oojs/i18n/be-tarask.json
deleted file mode 100644 (file)
index 5922f61..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "EugeneZelenko",
-            "Wizardist",
-            "Чаховіч Уладзіслаў",
-            "Zedlik"
-        ]
-    },
-    "ooui-dialog-action-close": "Закрыць",
-    "ooui-outline-control-move-down": "Перасунуць ніжэй",
-    "ooui-outline-control-move-up": "Перасунуць вышэй",
-    "ooui-toolbar-more": "Болей"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/be.json b/resources/oojs/i18n/be.json
deleted file mode 100644 (file)
index 3058ab8..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Чаховіч Уладзіслаў"
-        ]
-    },
-    "ooui-dialog-action-close": "Закрыць"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/bg.json b/resources/oojs/i18n/bg.json
deleted file mode 100644 (file)
index 67e664b..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "DCLXVI",
-            "Hristofor.mirchev",
-            "පසිඳු කාවින්ද"
-        ]
-    },
-    "ooui-dialog-action-close": "Затваряне",
-    "ooui-toolbar-more": "Още"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/bn.json b/resources/oojs/i18n/bn.json
deleted file mode 100644 (file)
index c321ab1..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Aftab1995",
-            "Bellayet",
-            "Jayantanth",
-            "Nasir8891",
-            "Runab",
-            "Sayak Sarkar"
-        ]
-    },
-    "ooui-dialog-action-close": "বন্ধ",
-    "ooui-outline-control-move-down": "আইটেম নিচে স্থানান্তর",
-    "ooui-outline-control-move-up": "আইটেম উপরে স্থানান্তর",
-    "ooui-toolbar-more": "আরও"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/br.json b/resources/oojs/i18n/br.json
deleted file mode 100644 (file)
index 38eb9e8..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Fohanno",
-            "Fulup",
-            "Y-M D"
-        ]
-    },
-    "ooui-dialog-action-close": "Serriñ",
-    "ooui-outline-control-move-down": "Lakaat an elfenn da ziskenn",
-    "ooui-outline-control-move-up": "Lakaat an elfenn da bignat"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/bs.json b/resources/oojs/i18n/bs.json
deleted file mode 100644 (file)
index 7449f07..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "DzWiki"
-        ]
-    },
-    "ooui-dialog-action-close": "Zatvori",
-    "ooui-outline-control-move-down": "Premjesti stavku dole",
-    "ooui-outline-control-move-up": "Premjesti stavku gore",
-    "ooui-toolbar-more": "Više"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/ca.json b/resources/oojs/i18n/ca.json
deleted file mode 100644 (file)
index 61bb1f6..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Alvaro Vidal-Abarca",
-            "Amire80",
-            "Arnaugir",
-            "Pginer",
-            "QuimGil",
-            "SMP",
-            "Vriullop"
-        ]
-    },
-    "ooui-dialog-action-close": "Tanca",
-    "ooui-outline-control-move-down": "Baixa element",
-    "ooui-outline-control-move-up": "Puja element",
-    "ooui-toolbar-more": "Més"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/ce.json b/resources/oojs/i18n/ce.json
deleted file mode 100644 (file)
index 1e145ea..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Amire80",
-            "Умар"
-        ]
-    },
-    "ooui-dialog-action-close": "ДӀачӀагӀа",
-    "ooui-outline-control-move-down": "Лаха яккха элемент",
-    "ooui-outline-control-move-up": "Лаккха яккха элемент",
-    "ooui-toolbar-more": "Кхин тӀе"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/ckb.json b/resources/oojs/i18n/ckb.json
deleted file mode 100644 (file)
index 839f4a8..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Calak",
-            "Muhammed taha"
-        ]
-    },
-    "ooui-dialog-action-close": "دایخە"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/co.json b/resources/oojs/i18n/co.json
deleted file mode 100644 (file)
index e5edb21..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Paulu"
-        ]
-    },
-    "ooui-dialog-action-close": "Chjude",
-    "ooui-outline-control-move-down": "Fà falà l'ogettu",
-    "ooui-outline-control-move-up": "Fà cullà l'ogettu"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/cs.json b/resources/oojs/i18n/cs.json
deleted file mode 100644 (file)
index 9661ec6..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Chmee2",
-            "Jkjk",
-            "Juandev",
-            "Koo6",
-            "Littledogboy",
-            "Michaelbrabec",
-            "Mormegil",
-            "Polda18",
-            "Tchoř",
-            "ශ්වෙත"
-        ]
-    },
-    "ooui-dialog-action-close": "Zavřít",
-    "ooui-outline-control-move-down": "Přesunout položku dolů",
-    "ooui-outline-control-move-up": "Přesunout položku nahoru",
-    "ooui-toolbar-more": "Další"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/cu.json b/resources/oojs/i18n/cu.json
deleted file mode 100644 (file)
index fa9b1cf..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "ОйЛ"
-        ]
-    },
-    "ooui-dialog-action-close": "ꙁакрꙑи"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/cy.json b/resources/oojs/i18n/cy.json
deleted file mode 100644 (file)
index d37912d..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Lloffiwr",
-            "Robin Owain",
-            "ОйЛ"
-        ]
-    },
-    "ooui-dialog-action-close": "Caeer",
-    "ooui-outline-control-move-down": "Symud yr eitem lawr",
-    "ooui-outline-control-move-up": "Symud yr eitem lan",
-    "ooui-toolbar-more": "Rhagor"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/da.json b/resources/oojs/i18n/da.json
deleted file mode 100644 (file)
index bf47bcb..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Cgtdk",
-            "Christian List",
-            "EileenSanda",
-            "Laketown",
-            "Palnatoke",
-            "Simeondahl",
-            "Tehnix"
-        ]
-    },
-    "ooui-dialog-action-close": "Luk",
-    "ooui-outline-control-move-down": "Flyt ned",
-    "ooui-outline-control-move-up": "Flyt op",
-    "ooui-toolbar-more": "Mere"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/de.json b/resources/oojs/i18n/de.json
deleted file mode 100644 (file)
index 3a66648..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "APPER",
-            "G.Hagedorn",
-            "Inkowik",
-            "Jcornelius",
-            "Jdforrester",
-            "Kghbln",
-            "Metalhead64",
-            "Murma174",
-            "Se4598",
-            "Tomabrafix"
-        ]
-    },
-    "ooui-dialog-action-close": "Schließen",
-    "ooui-outline-control-move-down": "Element nach unten verschieben",
-    "ooui-outline-control-move-up": "Element nach oben verschieben",
-    "ooui-toolbar-more": "Mehr"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/diq.json b/resources/oojs/i18n/diq.json
deleted file mode 100644 (file)
index bb0ac35..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Erdemaslancan",
-            "Gorizon",
-            "Kghbln",
-            "Marmase",
-            "Mirzali",
-            "Se4598"
-        ]
-    },
-    "ooui-dialog-action-close": "Racnê",
-    "ooui-outline-control-move-down": "Bendi bere cêr",
-    "ooui-outline-control-move-up": "Bendi bere cor",
-    "ooui-toolbar-more": "Zewbi"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/dsb.json b/resources/oojs/i18n/dsb.json
deleted file mode 100644 (file)
index 0f47587..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Michawiki"
-        ]
-    },
-    "ooui-dialog-action-close": "Zacyniś",
-    "ooui-outline-control-move-down": "Element dołoj pśesunuś",
-    "ooui-outline-control-move-up": "Element górjej pśesunuś",
-    "ooui-toolbar-more": "Wěcej"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/el.json b/resources/oojs/i18n/el.json
deleted file mode 100644 (file)
index 66051f1..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Astralnet",
-            "Dipa1965",
-            "Evropi",
-            "FocalPoint",
-            "Geraki",
-            "Glavkos",
-            "Nikosguard",
-            "Tifa93"
-        ]
-    },
-    "ooui-dialog-action-close": "Κλείσιμο",
-    "ooui-outline-control-move-down": "Μετακίνηση προς τα κάτω",
-    "ooui-outline-control-move-up": "Μετακίνηση προς τα πάνω",
-    "ooui-toolbar-more": "Περισσότερα"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/eml.json b/resources/oojs/i18n/eml.json
deleted file mode 100644 (file)
index 5dd09f5..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Gloria sah",
-            "Lévi"
-        ]
-    },
-    "ooui-dialog-action-close": "Sèra",
-    "ooui-outline-control-move-down": "Spôsta in bâs",
-    "ooui-outline-control-move-up": "Spôsta in êlt",
-    "ooui-toolbar-more": "Êter"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/en.json b/resources/oojs/i18n/en.json
deleted file mode 100644 (file)
index d402de8..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Trevor Parscal",
-            "Ed Sanders",
-            "James D. Forrester",
-            "Raimond Spekking",
-            "Erik Moeller",
-            "Moriel Schottlender",
-            "Yuki Shira",
-            "Siebrand Mazeland",
-            "Rob Moen",
-            "Timo Tijhof",
-            "Roan Kattouw",
-            "Christian Williams",
-            "Amir E. Aharoni"
-        ]
-    },
-    "ooui-dialog-action-close": "Close",
-    "ooui-outline-control-move-down": "Move item down",
-    "ooui-outline-control-move-up": "Move item up",
-    "ooui-toolbar-more": "More"
-}
diff --git a/resources/oojs/i18n/eo.json b/resources/oojs/i18n/eo.json
deleted file mode 100644 (file)
index 51f3261..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Happy5214",
-            "KuboF",
-            "Shirayuki",
-            "Yekrats"
-        ]
-    },
-    "ooui-dialog-action-close": "Fermi",
-    "ooui-outline-control-move-down": "Movi eron suben",
-    "ooui-outline-control-move-up": "Movi eron supren",
-    "ooui-toolbar-more": "Pli"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/es.json b/resources/oojs/i18n/es.json
deleted file mode 100644 (file)
index 0d822bc..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Armando-Martin",
-            "Aruizdr",
-            "Benfutbol10",
-            "DJ Nietzsche",
-            "Erdemaslancan",
-            "Fitoschido",
-            "Imre",
-            "Invadinado",
-            "Jdforrester",
-            "Jduranboger",
-            "PoLuX124",
-            "Ralgis",
-            "Thehelpfulone"
-        ]
-    },
-    "ooui-dialog-action-close": "Cerrar",
-    "ooui-outline-control-move-down": "Mover abajo",
-    "ooui-outline-control-move-up": "Mover arriba",
-    "ooui-toolbar-more": "Más"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/et.json b/resources/oojs/i18n/et.json
deleted file mode 100644 (file)
index 4af8dbe..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Avjoska",
-            "Pikne"
-        ]
-    },
-    "ooui-dialog-action-close": "Sule",
-    "ooui-outline-control-move-down": "Liiguta üksust allapoole",
-    "ooui-outline-control-move-up": "Liiguta üksust ülespoole",
-    "ooui-toolbar-more": "Veel"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/eu.json b/resources/oojs/i18n/eu.json
deleted file mode 100644 (file)
index 5d3f08b..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "An13sa",
-            "Unai Fdz. de Betoño",
-            "Xabier Armendaritz"
-        ]
-    },
-    "ooui-dialog-action-close": "Itxi",
-    "ooui-outline-control-move-down": "Mugitu itema beherantz",
-    "ooui-outline-control-move-up": "Mugitu itema gorantz",
-    "ooui-toolbar-more": "Gehiago"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/fa.json b/resources/oojs/i18n/fa.json
deleted file mode 100644 (file)
index 173acd7..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Dalba",
-            "Ebraminio",
-            "Jdforrester",
-            "Ladsgroup",
-            "Mjbmr",
-            "Nojan Madinehi",
-            "Reza1615",
-            "Taha",
-            "درفش کاویانی"
-        ]
-    },
-    "ooui-dialog-action-close": "بستن",
-    "ooui-outline-control-move-down": "انتقال مورد به پایین",
-    "ooui-outline-control-move-up": "انتقال مورد به بالا",
-    "ooui-toolbar-more": "بیشتر"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/fi.json b/resources/oojs/i18n/fi.json
deleted file mode 100644 (file)
index dcd367f..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Beluga",
-            "Crt",
-            "Harriv",
-            "Linnea",
-            "Nedergard",
-            "Nike",
-            "Olli",
-            "Pxos",
-            "Samoasambia",
-            "Silvonen",
-            "Skalman",
-            "Stryn",
-            "VezonThunder"
-        ]
-    },
-    "ooui-dialog-action-close": "Sulje",
-    "ooui-outline-control-move-down": "Siirrä kohdetta alaspäin",
-    "ooui-outline-control-move-up": "Siirrä kohdetta ylöspäin",
-    "ooui-toolbar-more": "Lisää"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/fo.json b/resources/oojs/i18n/fo.json
deleted file mode 100644 (file)
index 00a48ff..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "EileenSanda"
-        ]
-    },
-    "ooui-dialog-action-close": "Lat aftur",
-    "ooui-outline-control-move-down": "Flyt lutin niður",
-    "ooui-outline-control-move-up": "Flyt lutin upp",
-    "ooui-toolbar-more": "Meira"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/fr.json b/resources/oojs/i18n/fr.json
deleted file mode 100644 (file)
index eb24b5a..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Automatik",
-            "Benoit Rochon",
-            "Boniface",
-            "Brunoperel",
-            "Crochet.david",
-            "DavidL",
-            "Dereckson",
-            "Gomoko",
-            "Guillom",
-            "Hello71",
-            "Jean-Frédéric",
-            "Linedwell",
-            "Ltrlg",
-            "Metroitendo",
-            "NemesisIII",
-            "Nicolas NALLET",
-            "Npettiaux",
-            "Rastus Vernon",
-            "Seb35",
-            "Sherbrooke",
-            "Tpt",
-            "Trizek",
-            "Urhixidur",
-            "Verdy p",
-            "Wyz"
-        ]
-    },
-    "ooui-dialog-action-close": "Fermer",
-    "ooui-outline-control-move-down": "Faire descendre l’élément",
-    "ooui-outline-control-move-up": "Faire monter l’élément",
-    "ooui-toolbar-more": "Plus"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/frr.json b/resources/oojs/i18n/frr.json
deleted file mode 100644 (file)
index ee95b8a..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "ChrisPtDe",
-            "Murma174"
-        ]
-    },
-    "ooui-dialog-action-close": "Slütj",
-    "ooui-outline-control-move-down": "Element efter onern sküüw",
-    "ooui-outline-control-move-up": "Element efter boowen sküüw",
-    "ooui-toolbar-more": "Muar"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/fur.json b/resources/oojs/i18n/fur.json
deleted file mode 100644 (file)
index 18ea383..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Klenje",
-            "Tocaibon"
-        ]
-    },
-    "ooui-dialog-action-close": "Siere",
-    "ooui-outline-control-move-down": "sposte sot",
-    "ooui-outline-control-move-up": "sposte in su",
-    "ooui-toolbar-more": "Altri"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/gl.json b/resources/oojs/i18n/gl.json
deleted file mode 100644 (file)
index 5d0928f..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Alison",
-            "Kscanne",
-            "Toliño"
-        ]
-    },
-    "ooui-dialog-action-close": "Pechar",
-    "ooui-outline-control-move-down": "Mover o elemento abaixo",
-    "ooui-outline-control-move-up": "Mover o elemento arriba",
-    "ooui-toolbar-more": "Máis"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/gu.json b/resources/oojs/i18n/gu.json
deleted file mode 100644 (file)
index 65ec22b..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Ashok modhvadia",
-            "KartikMistry",
-            "The Discoverer"
-        ]
-    },
-    "ooui-dialog-action-close": "બંધ કરો",
-    "ooui-outline-control-move-down": "વસ્તુ નીચે ખસેડો",
-    "ooui-outline-control-move-up": "વસ્તુ ઉપર ખસેડો",
-    "ooui-toolbar-more": "વધુ"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/he.json b/resources/oojs/i18n/he.json
deleted file mode 100644 (file)
index 31b693c..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Amire80",
-            "ExampleTomer",
-            "Guycn2",
-            "Matanya",
-            "Mooeypoo",
-            "Orsa",
-            "Shimmin Beg",
-            "אור שפירא",
-            "חיים",
-            "ערן",
-            "פוילישער",
-            "קיפודנחש"
-        ]
-    },
-    "ooui-dialog-action-close": "סגירה",
-    "ooui-outline-control-move-down": "להזיז את הפריט מטה",
-    "ooui-outline-control-move-up": "להזיז את הפריט מעלה",
-    "ooui-toolbar-more": "עוד"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/hi.json b/resources/oojs/i18n/hi.json
deleted file mode 100644 (file)
index 8b79d34..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Ansumang",
-            "Devayon",
-            "Rajesh",
-            "Siddhartha Ghai"
-        ]
-    },
-    "ooui-dialog-action-close": "बंद करें",
-    "ooui-outline-control-move-down": "प्रविष्टि नीचे ले जाएँ",
-    "ooui-outline-control-move-up": "प्रविष्टि ऊपर ले जाएँ",
-    "ooui-toolbar-more": "अधिक"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/hr.json b/resources/oojs/i18n/hr.json
deleted file mode 100644 (file)
index 1c3f925..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "MaGa",
-            "Roberta F.",
-            "SpeedyGonsales"
-        ]
-    },
-    "ooui-dialog-action-close": "zatvori",
-    "ooui-outline-control-move-down": "Premjesti stavku dolje",
-    "ooui-outline-control-move-up": "Premjesti stavku gore",
-    "ooui-toolbar-more": "Više mogućnosti"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/hsb.json b/resources/oojs/i18n/hsb.json
deleted file mode 100644 (file)
index 861c6e5..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "J budissin",
-            "Michawiki"
-        ]
-    },
-    "ooui-dialog-action-close": "Začinić"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/hu.json b/resources/oojs/i18n/hu.json
deleted file mode 100644 (file)
index 9f7b435..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Dj",
-            "Einstein2",
-            "Misibacsi",
-            "ViDam"
-        ]
-    },
-    "ooui-dialog-action-close": "Bezár",
-    "ooui-outline-control-move-down": "Elem mozgatása lefelé",
-    "ooui-outline-control-move-up": "Elem mozgatása felfelé",
-    "ooui-toolbar-more": "Tovább..."
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/hy.json b/resources/oojs/i18n/hy.json
deleted file mode 100644 (file)
index f6cb90b..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Vacio",
-            "Xelgen"
-        ]
-    },
-    "ooui-dialog-action-close": "Փակել",
-    "ooui-outline-control-move-down": "Իջեցնել կետը",
-    "ooui-outline-control-move-up": "Բարձրացնել կետը",
-    "ooui-toolbar-more": "Ավելին"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/ia.json b/resources/oojs/i18n/ia.json
deleted file mode 100644 (file)
index e335553..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "McDutchie"
-        ]
-    },
-    "ooui-dialog-action-close": "Clauder"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/id.json b/resources/oojs/i18n/id.json
deleted file mode 100644 (file)
index 6d3ba4d..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Farras",
-            "Ilham151096",
-            "Iwan Novirion",
-            "Iyan",
-            "Kenrick95",
-            "McDutchie",
-            "Rv77ax",
-            "William Surya Permana"
-        ]
-    },
-    "ooui-dialog-action-close": "Tutup",
-    "ooui-outline-control-move-down": "Pindahkan butir ke bawah",
-    "ooui-outline-control-move-up": "Pindahkan butir ke atas",
-    "ooui-toolbar-more": "Lainnya"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/ie.json b/resources/oojs/i18n/ie.json
deleted file mode 100644 (file)
index 84d002d..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Makuba"
-        ]
-    },
-    "ooui-dialog-action-close": "Terminar",
-    "ooui-outline-control-move-down": "Mover element a infra",
-    "ooui-outline-control-move-up": "Mover element a supra",
-    "ooui-toolbar-more": "Plu"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/ilo.json b/resources/oojs/i18n/ilo.json
deleted file mode 100644 (file)
index 15f42e5..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Lam-ang"
-        ]
-    },
-    "ooui-dialog-action-close": "Irekep",
-    "ooui-outline-control-move-down": "Ipababa ti banag",
-    "ooui-outline-control-move-up": "Ipangato ti banag",
-    "ooui-toolbar-more": "Adu pay"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/is.json b/resources/oojs/i18n/is.json
deleted file mode 100644 (file)
index efe0e67..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Maxí",
-            "Snævar"
-        ]
-    },
-    "ooui-dialog-action-close": "Loka",
-    "ooui-outline-control-move-down": "Færa atriða niður",
-    "ooui-outline-control-move-up": "Færa atriða upp",
-    "ooui-toolbar-more": "Fleira"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/it.json b/resources/oojs/i18n/it.json
deleted file mode 100644 (file)
index 6158cff..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Beta16",
-            "Darth Kule",
-            "Doc.mari",
-            "Eleonora negri",
-            "Elitre",
-            "F. Cosoleto",
-            "FRacco",
-            "Gianfranco",
-            "Minerva Titani",
-            "Raoli",
-            "Una giornata uggiosa '94"
-        ]
-    },
-    "ooui-dialog-action-close": "Chiudi",
-    "ooui-outline-control-move-down": "Sposta in basso",
-    "ooui-outline-control-move-up": "Sposta in alto",
-    "ooui-toolbar-more": "Altro"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/ja.json b/resources/oojs/i18n/ja.json
deleted file mode 100644 (file)
index 789fbeb..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Fryed-peach",
-            "Miya",
-            "Penn Station",
-            "Shirayuki"
-        ]
-    },
-    "ooui-dialog-action-close": "閉じる",
-    "ooui-outline-control-move-down": "項目を下に移動させる",
-    "ooui-outline-control-move-up": "項目を上に移動させる",
-    "ooui-toolbar-more": "その他"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/jv.json b/resources/oojs/i18n/jv.json
deleted file mode 100644 (file)
index a362079..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Gleki",
-            "NoiX180",
-            "Pras"
-        ]
-    },
-    "ooui-dialog-action-close": "Tutup",
-    "ooui-outline-control-move-down": "Pindhahaken butir mangandhap"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/ka.json b/resources/oojs/i18n/ka.json
deleted file mode 100644 (file)
index 78180af..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "BRUTE",
-            "David1010",
-            "Gleki",
-            "ITshnik",
-            "MIKHEIL",
-            "NoiX180",
-            "Pras"
-        ]
-    },
-    "ooui-dialog-action-close": "დახურვა",
-    "ooui-outline-control-move-down": "ელემენტის ქვემოთ გადატანა",
-    "ooui-outline-control-move-up": "ელემენტის ზემოთ გადატანა"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/kk-cyrl.json b/resources/oojs/i18n/kk-cyrl.json
deleted file mode 100644 (file)
index 4c27b07..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Arystanbek"
-        ]
-    },
-    "ooui-dialog-action-close": "Жабу",
-    "ooui-outline-control-move-down": "Элементті төмен жылжыту",
-    "ooui-outline-control-move-up": "Элементті жоғары жылжыту",
-    "ooui-toolbar-more": "толығырақ"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/ko.json b/resources/oojs/i18n/ko.json
deleted file mode 100644 (file)
index f1f61df..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Freebiekr",
-            "Hym411",
-            "Kwj2772",
-            "LFM",
-            "아라"
-        ]
-    },
-    "ooui-dialog-action-close": "닫기",
-    "ooui-outline-control-move-down": "항목을 아래로 옮기기",
-    "ooui-outline-control-move-up": "항목을 위로 옮기기",
-    "ooui-toolbar-more": "더 보기"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/krc.json b/resources/oojs/i18n/krc.json
deleted file mode 100644 (file)
index f629139..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Iltever"
-        ]
-    },
-    "ooui-dialog-action-close": "Джаб",
-    "ooui-outline-control-move-down": "Элементни тюбюне кёчюр",
-    "ooui-outline-control-move-up": "Элементни башына кёчюр"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/kw.json b/resources/oojs/i18n/kw.json
deleted file mode 100644 (file)
index 95a9b91..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "George Animal",
-            "Nrowe",
-            "Purodha"
-        ]
-    },
-    "ooui-dialog-action-close": "Degea"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/ky.json b/resources/oojs/i18n/ky.json
deleted file mode 100644 (file)
index 2d62bda..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Chorobek",
-            "George Animal",
-            "Nrowe",
-            "Tynchtyk Chorotegin",
-            "Викиней"
-        ]
-    },
-    "ooui-dialog-action-close": "Жабуу"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/lb.json b/resources/oojs/i18n/lb.json
deleted file mode 100644 (file)
index a18894e..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Autokrator",
-            "Chorobek",
-            "Robby",
-            "Soued031",
-            "Tynchtyk Chorotegin",
-            "UV",
-            "Викиней"
-        ]
-    },
-    "ooui-dialog-action-close": "Zoumaachen",
-    "ooui-outline-control-move-down": "Element erof réckelen",
-    "ooui-outline-control-move-up": "Element erop réckelen",
-    "ooui-toolbar-more": "Méi"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/lmo.json b/resources/oojs/i18n/lmo.json
deleted file mode 100644 (file)
index e506b7a..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Ninonino"
-        ]
-    },
-    "ooui-dialog-action-close": "Sèra",
-    "ooui-outline-control-move-down": "Spòsta 'n zó",
-    "ooui-outline-control-move-up": "Spòsta 'n sö",
-    "ooui-toolbar-more": "Amò"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/lt.json b/resources/oojs/i18n/lt.json
deleted file mode 100644 (file)
index b3a16e8..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Audriusa",
-            "Eitvys200"
-        ]
-    },
-    "ooui-dialog-action-close": "Uždaryti"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/lv.json b/resources/oojs/i18n/lv.json
deleted file mode 100644 (file)
index c633339..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Admresdeserv.",
-            "Audriusa",
-            "Eitvys200",
-            "Papuass",
-            "PeterisP"
-        ]
-    },
-    "ooui-dialog-action-close": "Aizvērt",
-    "ooui-outline-control-move-down": "Pārvietot vienumu uz leju",
-    "ooui-outline-control-move-up": "Pārvietot vienumu uz augšu",
-    "ooui-toolbar-more": "Vairāk"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/mg.json b/resources/oojs/i18n/mg.json
deleted file mode 100644 (file)
index dcb5fd5..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Jagwar"
-        ]
-    },
-    "ooui-dialog-action-close": "Hidiana"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/min.json b/resources/oojs/i18n/min.json
deleted file mode 100644 (file)
index 55174c0..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Iwan Novirion",
-            "Jagwar"
-        ]
-    },
-    "ooui-dialog-action-close": "Tutuik"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/mk.json b/resources/oojs/i18n/mk.json
deleted file mode 100644 (file)
index b363a45..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Bjankuloski06",
-            "Brest",
-            "Iwan Novirion"
-        ]
-    },
-    "ooui-dialog-action-close": "Затвори",
-    "ooui-outline-control-move-down": "Помести надолу",
-    "ooui-outline-control-move-up": "Помести нагоре",
-    "ooui-toolbar-more": "Повеќе"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/ml.json b/resources/oojs/i18n/ml.json
deleted file mode 100644 (file)
index 355e337..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Kavya Manohar",
-            "Praveenp",
-            "Santhosh.thottingal",
-            "Vssun"
-        ]
-    },
-    "ooui-dialog-action-close": "അടയ്ക്കുക",
-    "ooui-outline-control-move-down": "ഇനം താഴേയ്ക്ക് മാറ്റുക",
-    "ooui-outline-control-move-up": "ഇനം മുകളിലേയ്ക്ക് മാറ്റുക",
-    "ooui-toolbar-more": "കൂടുതൽ"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/mr.json b/resources/oojs/i18n/mr.json
deleted file mode 100644 (file)
index d4db84f..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Kaajawa",
-            "Mahitgar",
-            "Praju23",
-            "V.narsikar",
-            "Ydyashad",
-            "संतोष दहिवळ"
-        ]
-    },
-    "ooui-dialog-action-close": "बंद करा",
-    "ooui-outline-control-move-down": "घटक (आयटम) खाली सरकवा",
-    "ooui-outline-control-move-up": "घटक (आयटम) वर सरकवा",
-    "ooui-toolbar-more": "अधिक"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/ms.json b/resources/oojs/i18n/ms.json
deleted file mode 100644 (file)
index 21aef50..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Anakmalaysia",
-            "Aurora"
-        ]
-    },
-    "ooui-dialog-action-close": "Tutup",
-    "ooui-outline-control-move-down": "Alihkan perkara ke bawah",
-    "ooui-outline-control-move-up": "Alihkan perkara ke atas",
-    "ooui-toolbar-more": "Lagi"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/nap.json b/resources/oojs/i18n/nap.json
deleted file mode 100644 (file)
index 6b0b3ec..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Chelin",
-            "Chrisportelli",
-            "PiRSquared17"
-        ]
-    },
-    "ooui-dialog-action-close": "Chiure",
-    "ooui-toolbar-more": "Atro"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/nb.json b/resources/oojs/i18n/nb.json
deleted file mode 100644 (file)
index 7cdecaa..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Danmichaelo",
-            "Event",
-            "Jeblad",
-            "Laaknor",
-            "Njardarlogar"
-        ]
-    },
-    "ooui-dialog-action-close": "Lukk",
-    "ooui-outline-control-move-down": "Flytt ned",
-    "ooui-outline-control-move-up": "Flytt opp",
-    "ooui-toolbar-more": "Mer"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/nds-nl.json b/resources/oojs/i18n/nds-nl.json
deleted file mode 100644 (file)
index 81f8a43..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Servien"
-        ]
-    },
-    "ooui-dialog-action-close": "Sluten",
-    "ooui-outline-control-move-down": "Onderwarp ummeneer zetten",
-    "ooui-outline-control-move-up": "Onderwarp umhoge zetten"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/nds.json b/resources/oojs/i18n/nds.json
deleted file mode 100644 (file)
index d0806d0..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Zylbath"
-        ]
-    },
-    "ooui-dialog-action-close": "Dichtmaken",
-    "ooui-outline-control-move-down": "Element na ünnen schuven",
-    "ooui-outline-control-move-up": "Element na baven schuven",
-    "ooui-toolbar-more": "Mehr"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/ne.json b/resources/oojs/i18n/ne.json
deleted file mode 100644 (file)
index ae948c6..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "RajeshPandey",
-            "सरोज कुमार ढकाल"
-        ]
-    }
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/nl.json b/resources/oojs/i18n/nl.json
deleted file mode 100644 (file)
index 75db0a7..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Bluyten",
-            "Breghtje",
-            "Catrope",
-            "Flightmare",
-            "Hansmuller",
-            "Jdforrester",
-            "Keegan",
-            "Konovalov",
-            "RajeshPandey",
-            "Romaine",
-            "SPQRobin",
-            "Saruman",
-            "Siebrand",
-            "Southparkfan",
-            "सरोज कुमार ढकाल"
-        ]
-    },
-    "ooui-dialog-action-close": "Sluiten",
-    "ooui-outline-control-move-down": "Item omlaag verplaatsen",
-    "ooui-outline-control-move-up": "Item omhoog verplaatsen",
-    "ooui-toolbar-more": "Meer"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/nn.json b/resources/oojs/i18n/nn.json
deleted file mode 100644 (file)
index dd86f5e..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Jeblad",
-            "Njardarlogar"
-        ]
-    },
-    "ooui-dialog-action-close": "Lat att",
-    "ooui-outline-control-move-down": "Flytt element ned",
-    "ooui-outline-control-move-up": "Flytt element opp",
-    "ooui-toolbar-more": "Fleire"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/om.json b/resources/oojs/i18n/om.json
deleted file mode 100644 (file)
index dca7b7d..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Cedric31",
-            "Tumsaa"
-        ]
-    },
-    "ooui-dialog-action-close": "Cufi",
-    "ooui-outline-control-move-down": "Gad buusi",
-    "ooui-outline-control-move-up": "Ol baasi",
-    "ooui-toolbar-more": "Dabalata"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/or.json b/resources/oojs/i18n/or.json
deleted file mode 100644 (file)
index 35721a1..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Odisha1",
-            "Psubhashish",
-            "ଶିତିକଣ୍ଠ ଦାଶ"
-        ]
-    },
-    "ooui-dialog-action-close": "ବନ୍ଦ କରିବେ"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/pa.json b/resources/oojs/i18n/pa.json
deleted file mode 100644 (file)
index 6c76d7f..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Amikeco",
-            "Babanwalia",
-            "Bouron",
-            "Nasir8891"
-        ]
-    },
-    "ooui-dialog-action-close": "বন্ধ"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/pl.json b/resources/oojs/i18n/pl.json
deleted file mode 100644 (file)
index ba33322..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Babanwalia",
-            "Chrumps",
-            "Matma Rex",
-            "Mikołka",
-            "Nasir8891",
-            "Odie2",
-            "Rzuwig",
-            "Tar Lócesilion",
-            "Ty221",
-            "WTM",
-            "Woytecr",
-            "Wpedzich"
-        ]
-    },
-    "ooui-dialog-action-close": "Zamknij",
-    "ooui-outline-control-move-down": "Przenieś niżej",
-    "ooui-outline-control-move-up": "Przenieś wyżej",
-    "ooui-toolbar-more": "Więcej"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/pms.json b/resources/oojs/i18n/pms.json
deleted file mode 100644 (file)
index bb8f113..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Borichèt",
-            "Dragonòt",
-            "පසිඳු කාවින්ද"
-        ]
-    },
-    "ooui-dialog-action-close": "Saré",
-    "ooui-outline-control-move-down": "Fé calé giù l'element",
-    "ooui-outline-control-move-up": "Fé monté l'element",
-    "ooui-toolbar-more": "Ëd pi"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/ps.json b/resources/oojs/i18n/ps.json
deleted file mode 100644 (file)
index 4f21707..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Ahmed-Najib-Biabani-Ibrahimkhel"
-        ]
-    },
-    "ooui-dialog-action-close": "تړل",
-    "ooui-outline-control-move-down": "توکی ښکته راوړل",
-    "ooui-outline-control-move-up": "توکی پورته راوړل",
-    "ooui-toolbar-more": "نور"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/pt-br.json b/resources/oojs/i18n/pt-br.json
deleted file mode 100644 (file)
index f758660..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Cainamarques",
-            "Dianakc",
-            "Fúlvio",
-            "Helder.wiki",
-            "HenriqueCrang",
-            "Jaideraf",
-            "Luckas",
-            "OTAVIO1981",
-            555
-        ]
-    },
-    "ooui-dialog-action-close": "Fechar",
-    "ooui-outline-control-move-down": "Mover item para baixo",
-    "ooui-outline-control-move-up": "Mover item para cima",
-    "ooui-toolbar-more": "Mais"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/pt.json b/resources/oojs/i18n/pt.json
deleted file mode 100644 (file)
index a4dba27..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Cainamarques",
-            "Fúlvio",
-            "GoEThe",
-            "Hamilton Abreu",
-            "Helder.wiki",
-            "Jaideraf",
-            "Jdforrester",
-            "Luckas",
-            "Vitorvicentevalente"
-        ]
-    },
-    "ooui-dialog-action-close": "Fechar",
-    "ooui-outline-control-move-down": "Mover item para baixo",
-    "ooui-outline-control-move-up": "Mover item para cima",
-    "ooui-toolbar-more": "Mais"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/qqq.json b/resources/oojs/i18n/qqq.json
deleted file mode 100644 (file)
index 78a70d9..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Amire80",
-            "Beta16",
-            "Erik Moeller",
-            "Jdforrester",
-            "Lloffiwr",
-            "Mooeypoo",
-            "Mormegil",
-            "Nike",
-            "PoLuX124",
-            "Purodha",
-            "Raymond",
-            "Sagan",
-            "Sayak Sarkar",
-            "Shirayuki",
-            "Siebrand",
-            "Trevor Parscal"
-        ]
-    },
-    "ooui-dialog-action-close": "Label text for button to exit from dialog.\n\n{{Identical|Close}}",
-    "ooui-outline-control-move-down": "Tool tip for a button that moves items in a list down one place",
-    "ooui-outline-control-move-up": "Tool tip for a button that moves items in a list up one place",
-    "ooui-toolbar-more": "Label for the toolbar group that contains a list of all other available tools.\n{{Identical|More}}"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/qu.json b/resources/oojs/i18n/qu.json
deleted file mode 100644 (file)
index 9a412f5..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "AlimanRuna"
-        ]
-    },
-    "ooui-dialog-action-close": "Wichq'ay",
-    "ooui-outline-control-move-down": "Qallawata uraykuchiy",
-    "ooui-outline-control-move-up": "Qallawata huqariy",
-    "ooui-toolbar-more": "Aswan"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/ro.json b/resources/oojs/i18n/ro.json
deleted file mode 100644 (file)
index 861b2fe..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "AlimanRuna",
-            "Firilacroco",
-            "Minisarm",
-            "Stelistcristi"
-        ]
-    },
-    "ooui-dialog-action-close": "Închide",
-    "ooui-outline-control-move-down": "Mută elementul mai jos",
-    "ooui-outline-control-move-up": "Mută elementul mai sus",
-    "ooui-toolbar-more": "Mai mult"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/roa-tara.json b/resources/oojs/i18n/roa-tara.json
deleted file mode 100644 (file)
index c7699d6..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Joetaras"
-        ]
-    },
-    "ooui-dialog-action-close": "Achiude",
-    "ooui-outline-control-move-down": "Spuèste 'a vôsce sotte",
-    "ooui-outline-control-move-up": "Spuèste 'a vôsce sus",
-    "ooui-toolbar-more": "De cchiù"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/ru.json b/resources/oojs/i18n/ru.json
deleted file mode 100644 (file)
index be7c6a5..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Amire80",
-            "DR",
-            "Eugrus",
-            "Iluvatar",
-            "KPu3uC B Poccuu",
-            "Kalan",
-            "MaxBioHazard",
-            "NBS",
-            "Niklem",
-            "Okras",
-            "Ole Yves",
-            "Putnik",
-            "Sunpriat",
-            "Yury Katkov",
-            "Умар"
-        ]
-    },
-    "ooui-dialog-action-close": "Закрыть",
-    "ooui-outline-control-move-down": "Переместить элемент вниз",
-    "ooui-outline-control-move-up": "Переместить элемент вверх",
-    "ooui-toolbar-more": "Ещё"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/sah.json b/resources/oojs/i18n/sah.json
deleted file mode 100644 (file)
index 9b3fcc8..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Gazeb",
-            "HalanTul"
-        ]
-    },
-    "ooui-dialog-action-close": "Сап"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/scn.json b/resources/oojs/i18n/scn.json
deleted file mode 100644 (file)
index a699911..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Gazeb",
-            "Gmelfi",
-            "HalanTul"
-        ]
-    },
-    "ooui-dialog-action-close": "Chiùi",
-    "ooui-outline-control-move-down": "Sposta di sutta",
-    "ooui-outline-control-move-up": "Sposta di supra",
-    "ooui-toolbar-more": "Àutri cosi"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/sh.json b/resources/oojs/i18n/sh.json
deleted file mode 100644 (file)
index 5e29980..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "OC Ripper"
-        ]
-    },
-    "ooui-dialog-action-close": "Zatvori",
-    "ooui-outline-control-move-down": "Pomakni stavku dolje",
-    "ooui-outline-control-move-up": "Pomakni stavku gore"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/si.json b/resources/oojs/i18n/si.json
deleted file mode 100644 (file)
index cf7a9fd..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Singhalawap",
-            "පසිඳු කාවින්ද",
-            "ශ්වෙත"
-        ]
-    },
-    "ooui-dialog-action-close": "නිමවන්න",
-    "ooui-outline-control-move-down": "අයිතමය පහලටදමන්න",
-    "ooui-outline-control-move-up": "අයිතමය ඉහලටදමන්න"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/sk.json b/resources/oojs/i18n/sk.json
deleted file mode 100644 (file)
index 60b6f43..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Mimarik",
-            "Teslaton"
-        ]
-    },
-    "ooui-dialog-action-close": "Zatvoriť",
-    "ooui-outline-control-move-down": "Posunúť položku nadol",
-    "ooui-outline-control-move-up": "Posunúť položku nahor",
-    "ooui-toolbar-more": "Viac"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/sl.json b/resources/oojs/i18n/sl.json
deleted file mode 100644 (file)
index d5bffd9..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Dbc334",
-            "Eleassar",
-            "Pinky sl",
-            "Yerpo"
-        ]
-    },
-    "ooui-dialog-action-close": "Zapri",
-    "ooui-outline-control-move-down": "Prestavi predmet nižje",
-    "ooui-outline-control-move-up": "Prestavi predmet višje",
-    "ooui-toolbar-more": "Več"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/sq.json b/resources/oojs/i18n/sq.json
deleted file mode 100644 (file)
index 424f1be..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Euriditi"
-        ]
-    },
-    "ooui-dialog-action-close": "Mbylle",
-    "ooui-outline-control-move-down": "Zhvendose artikullin më poshtë",
-    "ooui-outline-control-move-up": "Zhvendose artikullin më lart",
-    "ooui-toolbar-more": "Më tepër..."
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/sr-ec.json b/resources/oojs/i18n/sr-ec.json
deleted file mode 100644 (file)
index 973baec..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Milicevic01",
-            "Nikola Smolenski",
-            "Милан Јелисавчић"
-        ]
-    },
-    "ooui-dialog-action-close": "Затвори",
-    "ooui-outline-control-move-down": "Премести ставку на доле",
-    "ooui-outline-control-move-up": "Премести ставку на горе",
-    "ooui-toolbar-more": "Више"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/sv.json b/resources/oojs/i18n/sv.json
deleted file mode 100644 (file)
index 74d654b..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Ainali",
-            "Haxpett",
-            "Jopparn",
-            "Knuckles",
-            "Magol",
-            "Milicevic01",
-            "Per",
-            "Sendelbach",
-            "Skalman",
-            "WikiPhoenix"
-        ]
-    },
-    "ooui-dialog-action-close": "Stäng",
-    "ooui-outline-control-move-down": "Flytta ned objekt",
-    "ooui-outline-control-move-up": "Flytta upp objekt",
-    "ooui-toolbar-more": "Mer"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/sw.json b/resources/oojs/i18n/sw.json
deleted file mode 100644 (file)
index 1c61b06..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Lloffiwr",
-            "Muddyb Blast Producer"
-        ]
-    },
-    "ooui-dialog-action-close": "Funga",
-    "ooui-outline-control-move-down": "Sogeza kipengee chini",
-    "ooui-outline-control-move-up": "Sogeza kipengee juu",
-    "ooui-toolbar-more": "Zaidi"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/ta.json b/resources/oojs/i18n/ta.json
deleted file mode 100644 (file)
index a9795fd..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Jayarathina",
-            "Sank",
-            "Shanmugamp7",
-            "மதனாஹரன்"
-        ]
-    },
-    "ooui-dialog-action-close": "மூடுக"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/te.json b/resources/oojs/i18n/te.json
deleted file mode 100644 (file)
index a1f1285..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Arjunaraoc",
-            "Jayarathina",
-            "Sank",
-            "Shanmugamp7",
-            "Veeven",
-            "Visdaviva",
-            "மதனாஹரன்"
-        ]
-    },
-    "ooui-dialog-action-close": "మూయి"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/th.json b/resources/oojs/i18n/th.json
deleted file mode 100644 (file)
index b7ee05a..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Supasate",
-            "Taweetham"
-        ]
-    },
-    "ooui-dialog-action-close": "ปิด",
-    "ooui-outline-control-move-down": "เลื่อนรายการลง",
-    "ooui-outline-control-move-up": "ย้ายรายการขึ้น"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/tl.json b/resources/oojs/i18n/tl.json
deleted file mode 100644 (file)
index a073882..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "AnakngAraw",
-            "Sky Harbor"
-        ]
-    },
-    "ooui-dialog-action-close": "Isara",
-    "ooui-outline-control-move-down": "Ilipat ang aytem pababa",
-    "ooui-outline-control-move-up": "Ilipat ang aytem pataas",
-    "ooui-toolbar-more": "Marami pa"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/tr.json b/resources/oojs/i18n/tr.json
deleted file mode 100644 (file)
index 94d34a2..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Emperyan",
-            "Incelemeelemani",
-            "LuCKY",
-            "Maidis",
-            "Rapsar",
-            "Talha Samil Cakir",
-            "TurkishStyles"
-        ]
-    },
-    "ooui-dialog-action-close": "Kapat",
-    "ooui-outline-control-move-down": "Ögeyi aşağı taşı",
-    "ooui-outline-control-move-up": "Ögeyi yukarı taşı",
-    "ooui-toolbar-more": "Daha fazla"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/tt-cyrl.json b/resources/oojs/i18n/tt-cyrl.json
deleted file mode 100644 (file)
index 1c0bd90..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Ajdar"
-        ]
-    },
-    "ooui-dialog-action-close": "Ябу",
-    "ooui-outline-control-move-down": "Элементны аска күчерү",
-    "ooui-outline-control-move-up": "Элементны өскә күчерү"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/ug-arab.json b/resources/oojs/i18n/ug-arab.json
deleted file mode 100644 (file)
index efba086..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Sahran",
-            "Tel'et",
-            "Tifinaghes"
-        ]
-    }
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/uk.json b/resources/oojs/i18n/uk.json
deleted file mode 100644 (file)
index 9a47ad7..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "AS",
-            "Aced",
-            "Ahonc",
-            "Andriykopanytsia",
-            "Base",
-            "Perohanych",
-            "RLuts",
-            "Sahran",
-            "Sergento",
-            "Steve.rusyn",
-            "SteveR",
-            "Tel'et",
-            "Tifinaghes",
-            "Ата"
-        ]
-    },
-    "ooui-dialog-action-close": "Закрити",
-    "ooui-outline-control-move-down": "Перемістити елемент униз",
-    "ooui-outline-control-move-up": "Перемістити елемент вгору",
-    "ooui-toolbar-more": "Більше"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/uz.json b/resources/oojs/i18n/uz.json
deleted file mode 100644 (file)
index 473fc75..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "CoderSI",
-            "Noor2020",
-            "Sociologist",
-            "පසිඳු කාවින්ද"
-        ]
-    },
-    "ooui-dialog-action-close": "Yopish",
-    "ooui-outline-control-move-down": "Elementni pastga koʻchirish",
-    "ooui-outline-control-move-up": "Elementni yuqoriga koʻchirish",
-    "ooui-toolbar-more": "Yana"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/vec.json b/resources/oojs/i18n/vec.json
deleted file mode 100644 (file)
index 01833f7..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Candalua",
-            "GatoSelvadego"
-        ]
-    },
-    "ooui-dialog-action-close": "Sara",
-    "ooui-outline-control-move-down": "Sposta in baso",
-    "ooui-outline-control-move-up": "Sposta in sima",
-    "ooui-toolbar-more": "Altro"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/vi.json b/resources/oojs/i18n/vi.json
deleted file mode 100644 (file)
index b545ce6..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Cheers!",
-            "Jdforrester",
-            "Minh Nguyen"
-        ]
-    },
-    "ooui-dialog-action-close": "Đóng",
-    "ooui-outline-control-move-down": "Chuyển mục xuống",
-    "ooui-outline-control-move-up": "Chuyển mục lên",
-    "ooui-toolbar-more": "Thêm"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/vo.json b/resources/oojs/i18n/vo.json
deleted file mode 100644 (file)
index 2ed7e2f..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Malafaya"
-        ]
-    },
-    "ooui-dialog-action-close": "Färmükön",
-    "ooui-toolbar-more": "Pluikos"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/wuu.json b/resources/oojs/i18n/wuu.json
deleted file mode 100644 (file)
index 72aa48b..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Malafaya",
-            "十弌"
-        ]
-    },
-    "ooui-toolbar-more": "還多"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/yi.json b/resources/oojs/i18n/yi.json
deleted file mode 100644 (file)
index ab5c510..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Malafaya",
-            "פוילישער",
-            "十弌"
-        ]
-    },
-    "ooui-dialog-action-close": "שליסן",
-    "ooui-outline-control-move-down": "רוקן עלעמענט אראפ",
-    "ooui-outline-control-move-up": "רוקן עלעמענט ארויף",
-    "ooui-toolbar-more": "נאך"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/yo.json b/resources/oojs/i18n/yo.json
deleted file mode 100644 (file)
index f71d3dd..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Demmy"
-        ]
-    },
-    "ooui-dialog-action-close": "Ìpadé",
-    "ooui-outline-control-move-down": "Sún onítòún sí sàlẹ̀",
-    "ooui-outline-control-move-up": "Sún onítòún s'ókè",
-    "ooui-toolbar-more": "Míràn"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/zh-hans.json b/resources/oojs/i18n/zh-hans.json
deleted file mode 100644 (file)
index 46cbae3..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Anakmalaysia",
-            "Bencmq",
-            "Demmy",
-            "Hydra",
-            "Hzy980512",
-            "Liangent",
-            "Liuxinyu970226",
-            "Qiyue2001",
-            "Shirayuki",
-            "Shizhao",
-            "TianyinLee",
-            "Xiaomingyan",
-            "Yfdyh000",
-            "Zhangjintao",
-            "乌拉跨氪"
-        ]
-    },
-    "ooui-dialog-action-close": "关闭",
-    "ooui-outline-control-move-down": "下移项",
-    "ooui-outline-control-move-up": "上移项",
-    "ooui-toolbar-more": "更多"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/zh-hant.json b/resources/oojs/i18n/zh-hant.json
deleted file mode 100644 (file)
index 9aace2f..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-{
-    "@metadata": {
-        "authors": [
-            "Anakmalaysia",
-            "Ch.Andrew",
-            "Hydra",
-            "Justincheng12345",
-            "Liflon",
-            "Liuxinyu970226",
-            "Qiyue2001",
-            "Radish10cm",
-            "Shirayuki",
-            "Simon Shek",
-            "Spring Roll Conan",
-            "Waihorace"
-        ]
-    },
-    "ooui-dialog-action-close": "關閉",
-    "ooui-outline-control-move-down": "向下移項",
-    "ooui-outline-control-move-up": "向上移項",
-    "ooui-toolbar-more": "更多"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/zh-hk.json b/resources/oojs/i18n/zh-hk.json
deleted file mode 100644 (file)
index 60e8fbd..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-{
-    "@metadata": [],
-    "ooui-dialog-action-close": "關閉"
-}
\ No newline at end of file
diff --git a/resources/oojs/i18n/zh-tw.json b/resources/oojs/i18n/zh-tw.json
deleted file mode 100644 (file)
index f7987e5..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-{
-    "@metadata": [],
-    "ooui-dialog-action-close": "關閉",
-    "ooui-outline-control-move-down": "向下移",
-    "ooui-outline-control-move-up": "向上移",
-    "ooui-toolbar-more": "更多"
-}
\ No newline at end of file
diff --git a/resources/oojs/images/fade-down.png b/resources/oojs/images/fade-down.png
deleted file mode 100644 (file)
index 50c7931..0000000
Binary files a/resources/oojs/images/fade-down.png and /dev/null differ
diff --git a/resources/oojs/images/fade-up.png b/resources/oojs/images/fade-up.png
deleted file mode 100644 (file)
index 7a0cb87..0000000
Binary files a/resources/oojs/images/fade-up.png and /dev/null differ
diff --git a/resources/oojs/images/icons/accept.png b/resources/oojs/images/icons/accept.png
deleted file mode 100644 (file)
index 1075110..0000000
Binary files a/resources/oojs/images/icons/accept.png and /dev/null differ
diff --git a/resources/oojs/images/icons/accept.svg b/resources/oojs/images/icons/accept.svg
deleted file mode 100644 (file)
index df78186..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="iso-8859-1"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px"
-        height="24px" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
-<g id="apply" style="opacity:0.75;">
-       <polygon id="check" style="fill-rule:evenodd;clip-rule:evenodd;" points="19.062,5.139 17.418,4 8.867,16.357 5.413,12.903 4,14.316 9.021,19.338"/>
-</g>
-</svg>
diff --git a/resources/oojs/images/icons/add-item.png b/resources/oojs/images/icons/add-item.png
deleted file mode 100644 (file)
index aa36cd0..0000000
Binary files a/resources/oojs/images/icons/add-item.png and /dev/null differ
diff --git a/resources/oojs/images/icons/add-item.svg b/resources/oojs/images/icons/add-item.svg
deleted file mode 100644 (file)
index ff95399..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24" height="24" viewBox="0, 0, 24, 24">
-  <g id="add-item">
-    <path d="M13,8 L11,8 L11,11 L8,11 L8,13 L11,13 L11,16 L13,16 L13,13 L16,13 L16,11 L13,11 z" fill="#000000"/>
-  </g>
-  <defs/>
-</svg>
diff --git a/resources/oojs/images/icons/advanced.png b/resources/oojs/images/icons/advanced.png
deleted file mode 100644 (file)
index 7f5ada5..0000000
Binary files a/resources/oojs/images/icons/advanced.png and /dev/null differ
diff --git a/resources/oojs/images/icons/advanced.svg b/resources/oojs/images/icons/advanced.svg
deleted file mode 100644 (file)
index 3e87cab..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" encoding="iso-8859-1"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px"
-        height="24px" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
-<g id="settings" style="opacity:0.75;">
-       <path id="gear" style="fill-rule:evenodd;clip-rule:evenodd;" d="M20.869,13.476C20.948,12.994,21,12.504,21,12
-               s-0.052-0.994-0.131-1.476l-2.463-0.259c-0.149-0.556-0.367-1.082-0.648-1.57l1.558-1.924c-0.576-0.806-1.281-1.511-2.087-2.087
-               l-1.924,1.558c-0.488-0.281-1.015-0.499-1.57-0.648l-0.259-2.463C12.994,3.052,12.504,3,12,3s-0.994,0.052-1.476,0.131
-               l-0.259,2.463C9.71,5.743,9.184,5.961,8.695,6.242L6.771,4.685C5.966,5.261,5.261,5.966,4.685,6.771l1.558,1.924
-               c-0.281,0.488-0.499,1.015-0.648,1.57l-2.463,0.259C3.052,11.006,3,11.496,3,12s0.052,0.994,0.131,1.476l2.463,0.259
-               c0.149,0.556,0.367,1.082,0.648,1.57l-1.558,1.924c0.576,0.806,1.281,1.511,2.087,2.087l1.924-1.558
-               c0.488,0.281,1.015,0.499,1.57,0.648l0.259,2.463C11.006,20.948,11.496,21,12,21s0.994-0.052,1.476-0.131l0.259-2.463
-               c0.556-0.149,1.082-0.367,1.57-0.648l1.924,1.558c0.806-0.576,1.511-1.281,2.087-2.087l-1.558-1.924
-               c0.281-0.488,0.499-1.015,0.648-1.57L20.869,13.476z M12,15.998c-2.209,0-3.998-1.789-3.998-3.998S9.791,8.002,12,8.002
-               S15.998,9.791,15.998,12S14.209,15.998,12,15.998z"/>
-</g>
-</svg>
diff --git a/resources/oojs/images/icons/alert.png b/resources/oojs/images/icons/alert.png
deleted file mode 100644 (file)
index 992ea2a..0000000
Binary files a/resources/oojs/images/icons/alert.png and /dev/null differ
diff --git a/resources/oojs/images/icons/alert.svg b/resources/oojs/images/icons/alert.svg
deleted file mode 100644 (file)
index 886a7c0..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0" encoding="iso-8859-1"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px"
-        height="24px" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
-<g id="alert" style="opacity:0.75;">
-       <rect id="point" x="11" y="16" style="fill-rule:evenodd;clip-rule:evenodd;" width="2" height="2"/>
-       <polygon id="stroke" style="fill-rule:evenodd;clip-rule:evenodd;" points="13.516,10 10.516,10 11,15 13,15"/>
-       <path id="triangle" d="M12.017,5.974L19.536,19H4.496L12.017,5.974 M12.017,3.5c-0.544,0-1.088,0.357-1.5,1.071L2.532,18.402 C1.707,19.831,2.382,21,4.032,21H20c1.65,0,2.325-1.169,1.5-2.599L13.517,4.572C13.104,3.857,12.561,3.5,12.017,3.5L12.017,3.5z"/>
-</g>
-</svg>
diff --git a/resources/oojs/images/icons/arched-arrow-ltr.png b/resources/oojs/images/icons/arched-arrow-ltr.png
deleted file mode 100644 (file)
index 5db1c4d..0000000
Binary files a/resources/oojs/images/icons/arched-arrow-ltr.png and /dev/null differ
diff --git a/resources/oojs/images/icons/arched-arrow-ltr.svg b/resources/oojs/images/icons/arched-arrow-ltr.svg
deleted file mode 100644 (file)
index 5b343a5..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="iso-8859-1"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px"
-        height="24px" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
-<g id="arched-arrow-ltr" style="opacity:0.75;">
-       <path id="arrow" style="fill-rule:evenodd;clip-rule:evenodd;" d="M19.925,14.937l-2.391-6.901l-1.48,2.329 c-0.964-0.845-2.699-1.85-5.513-1.823c-4.887,0.046-6.524,4.244-6.524,4.244s2.753-2.639,6.925-1.949 c1.729,0.286,3.007,1.206,3.675,1.791l-1.474,2.319L19.925,14.937z"/>
-</g>
-</svg>
diff --git a/resources/oojs/images/icons/arched-arrow-rtl.png b/resources/oojs/images/icons/arched-arrow-rtl.png
deleted file mode 100644 (file)
index 7931971..0000000
Binary files a/resources/oojs/images/icons/arched-arrow-rtl.png and /dev/null differ
diff --git a/resources/oojs/images/icons/arched-arrow-rtl.svg b/resources/oojs/images/icons/arched-arrow-rtl.svg
deleted file mode 100644 (file)
index bb5f10e..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="iso-8859-1"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px"
-        height="24px" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
-<g id="arched-arrow-rtl" style="opacity:0.75;">
-       <path id="arrow" style="fill-rule:evenodd;clip-rule:evenodd;" d="M13.401,8.542c-2.814-0.027-4.549,0.978-5.513,1.823 l-1.48-2.329l-2.391,6.901l6.782,0.009l-1.474-2.319c0.668-0.584,1.945-1.504,3.675-1.791c4.172-0.69,6.925,1.949,6.925,1.949 S18.288,8.588,13.401,8.542z"/>
-</g>
-</svg>
diff --git a/resources/oojs/images/icons/check.png b/resources/oojs/images/icons/check.png
deleted file mode 100644 (file)
index 82c3cb4..0000000
Binary files a/resources/oojs/images/icons/check.png and /dev/null differ
diff --git a/resources/oojs/images/icons/check.svg b/resources/oojs/images/icons/check.svg
deleted file mode 100644 (file)
index e67cd6c..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24" height="24" viewBox="0, 0, 24, 24">
-  <g id="check">
-    <path d="M7.105,13.473 L8.527,12.05 L10.428,13.952 L15.238,7 L16.895,8.148 L10.635,17 z" fill="#000000"/>
-  </g>
-  <defs/>
-</svg>
diff --git a/resources/oojs/images/icons/clear.png b/resources/oojs/images/icons/clear.png
deleted file mode 100644 (file)
index 697dd62..0000000
Binary files a/resources/oojs/images/icons/clear.png and /dev/null differ
diff --git a/resources/oojs/images/icons/clear.svg b/resources/oojs/images/icons/clear.svg
deleted file mode 100644 (file)
index d83eb02..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="iso-8859-1"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px"
-        height="24px" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
-<g id="clear" style="opacity:0.75;">
-       <path id="circle_with_strike" style="fill-rule:evenodd;clip-rule:evenodd;" d="M11.999,5.022c-3.853,0-6.977,3.124-6.977,6.978 c0,3.853,3.124,6.978,6.977,6.978c3.854,0,6.979-3.125,6.979-6.978C18.978,8.146,15.853,5.022,11.999,5.022z M6.886,12 c0-1.092,0.572-3.25,0.93-2.929l7.113,7.113c0.488,0.525-1.837,0.931-2.93,0.931C9.174,17.114,6.886,14.824,6.886,12z M16.184,14.929L9.07,7.816c-0.445-0.483,1.837-0.931,2.929-0.931c2.827,0,5.115,2.289,5.115,5.114 C17.114,13.092,16.75,15.542,16.184,14.929z"/>
-</g>
-</svg>
diff --git a/resources/oojs/images/icons/close.png b/resources/oojs/images/icons/close.png
deleted file mode 100644 (file)
index f7eed9f..0000000
Binary files a/resources/oojs/images/icons/close.png and /dev/null differ
diff --git a/resources/oojs/images/icons/close.svg b/resources/oojs/images/icons/close.svg
deleted file mode 100644 (file)
index a0118c2..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="iso-8859-1"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px"
-        height="24px" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
-<g id="close" style="opacity:0.75;">
-       <polygon id="x" style="fill-rule:evenodd;clip-rule:evenodd;" points="18.717,6.697 17.303,5.283 12,10.586 6.697,5.283 5.283,6.697 10.586,12 5.283,17.303 6.697,18.717 12,13.414 17.303,18.717 18.717,17.303 13.414,12            "/>
-</g>
-</svg>
diff --git a/resources/oojs/images/icons/code.png b/resources/oojs/images/icons/code.png
deleted file mode 100644 (file)
index a5ebdbf..0000000
Binary files a/resources/oojs/images/icons/code.png and /dev/null differ
diff --git a/resources/oojs/images/icons/code.svg b/resources/oojs/images/icons/code.svg
deleted file mode 100644 (file)
index 6f1ed53..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
-        width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
-<g id="code" opacity="0.75">
-       <path id="left-bracket" d="M4,12v-1h1c1,0,1,0,1-1V7.614C6,7.1,6.024,6.718,6.073,6.472C6.127,6.22,6.212,6.009,6.33,5.839
-               C6.534,5.56,6.803,5.364,7.138,5.255C7.473,5.14,8.01,5,8.973,5H10v1H9.248c-0.457,0-0.77,0.191-0.936,0.408
-               C8.145,6.623,8,6.853,8,7.476v1.857c0,0.729-0.041,1.18-0.244,1.493c-0.2,0.307-0.562,0.529-1.09,0.667
-               c0.535,0.155,0.9,0.385,1.096,0.688C7.961,12.484,8,12.938,8,13.665v1.862c0,0.619,0.145,0.848,0.312,1.062
-               c0.166,0.22,0.479,0.407,0.936,0.407L10,17l0,0v1H8.973c-0.963,0-1.5-0.133-1.835-0.248c-0.335-0.109-0.604-0.307-0.808-0.591
-               c-0.118-0.165-0.203-0.374-0.257-0.625C6.024,16.283,6,15.9,6,15.387V13c0-1,0-1-1-1H4z"/>
-       <use transform="matrix(-1,0,0,1,24,0)" id="right-bracket" x="0" y="0" width="24" height="24" xlink:href="#left-bracket" />
-</g>
-</svg>
diff --git a/resources/oojs/images/icons/collapse.png b/resources/oojs/images/icons/collapse.png
deleted file mode 100644 (file)
index 38b796f..0000000
Binary files a/resources/oojs/images/icons/collapse.png and /dev/null differ
diff --git a/resources/oojs/images/icons/collapse.svg b/resources/oojs/images/icons/collapse.svg
deleted file mode 100644 (file)
index a89cebf..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="iso-8859-1"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px"
-        height="24px" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
-<g id="collapse" style="opacity:0.75;">
-       <polygon id="arrow" style="fill-rule:evenodd;clip-rule:evenodd;" points="6.697,15.714 12,10.412 17.303,15.714 18.717,14.3 12,7.583 5.283,14.3"/>
-</g>
-</svg>
diff --git a/resources/oojs/images/icons/comment.png b/resources/oojs/images/icons/comment.png
deleted file mode 100644 (file)
index 9546455..0000000
Binary files a/resources/oojs/images/icons/comment.png and /dev/null differ
diff --git a/resources/oojs/images/icons/comment.svg b/resources/oojs/images/icons/comment.svg
deleted file mode 100644 (file)
index e052935..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="iso-8859-1"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px"
-        height="24px" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
-<g id="comment" style="opacity:0.75;">
-       <path id="speech_bubble" style="fill-rule:evenodd;clip-rule:evenodd;" d="M15,6H9C7.343,6,6,7.344,6,9v4c0,1.656,1.343,3,3,3v3 l3-3h3c1.657,0,3-1.344,3-3V9C18,7.344,16.657,6,15,6z"/>
-</g>
-</svg>
diff --git a/resources/oojs/images/icons/expand.png b/resources/oojs/images/icons/expand.png
deleted file mode 100644 (file)
index e90aca1..0000000
Binary files a/resources/oojs/images/icons/expand.png and /dev/null differ
diff --git a/resources/oojs/images/icons/expand.svg b/resources/oojs/images/icons/expand.svg
deleted file mode 100644 (file)
index b542f5f..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="iso-8859-1"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px"
-        height="24px" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
-<g id="expand" style="opacity:0.75;">
-       <polygon id="arrow" style="fill-rule:evenodd;clip-rule:evenodd;" points="17.303,8.283 12,13.586 6.697,8.283 5.283,9.697 12,16.414 18.717,9.697"/>
-</g>
-</svg>
diff --git a/resources/oojs/images/icons/help.png b/resources/oojs/images/icons/help.png
deleted file mode 100644 (file)
index dca745b..0000000
Binary files a/resources/oojs/images/icons/help.png and /dev/null differ
diff --git a/resources/oojs/images/icons/help.svg b/resources/oojs/images/icons/help.svg
deleted file mode 100644 (file)
index c68bdda..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="iso-8859-1"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px"
-        height="24px" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
-<g id="help" style="opacity:0.75;">
-       <path id="circle" style="fill-rule:evenodd;clip-rule:evenodd;" d="M12.001,2.085c-5.478,0-9.916,4.438-9.916,9.916 c0,5.476,4.438,9.914,9.916,9.914c5.476,0,9.914-4.438,9.914-9.914C21.915,6.523,17.477,2.085,12.001,2.085z M12.002,20.085 c-4.465,0-8.084-3.619-8.084-8.083c0-4.465,3.619-8.084,8.084-8.084c4.464,0,8.083,3.619,8.083,8.084 C20.085,16.466,16.466,20.085,12.002,20.085z"/>
-       <g id="question_mark">
-               <path id="top" style="fill-rule:evenodd;clip-rule:evenodd;" d="M11.766,6.688c-2.5,0-3.219,2.188-3.219,2.188l1.411,0.854 c0,0,0.298-0.791,0.901-1.229c0.516-0.375,1.625-0.625,2.219,0.125c0.701,0.885-0.17,1.587-1.078,2.719 C11.047,12.531,11,15,11,15h1.969c0,0,0.135-2.318,1.041-3.381c0.603-0.707,1.443-1.338,1.443-2.494S14.266,6.688,11.766,6.688z"/>
-               <rect id="bottom" x="11" y="16" style="fill-rule:evenodd;clip-rule:evenodd;" width="2" height="2"/>
-       </g>
-</g>
-</svg>
diff --git a/resources/oojs/images/icons/history.png b/resources/oojs/images/icons/history.png
deleted file mode 100644 (file)
index c049931..0000000
Binary files a/resources/oojs/images/icons/history.png and /dev/null differ
diff --git a/resources/oojs/images/icons/history.svg b/resources/oojs/images/icons/history.svg
deleted file mode 100644 (file)
index 40c0ae3..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="iso-8859-1"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px"
-        height="24px" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
-<g id="history" style="opacity:0.75;">
-       <path id="clock_hands" style="fill-rule:evenodd;clip-rule:evenodd;" d="M17.26,15.076c0,0-2.385-1.935-4.005-3.062 c0.72-2.397,1.702-6.559,1.702-6.559s-4.35,5.363-4.877,6.699c-0.463,1.168,1.459,2.209,2.346,1.678 C14.326,14.383,17.26,15.076,17.26,15.076z"/>
-       <path id="arrow" style="fill-rule:evenodd;clip-rule:evenodd;" d="M12.086,2.085c-5.478,0-9.916,4.438-9.916,9.916 c0,1.783,0.476,3.454,1.301,4.898l-2.223,2.04h5.688v-5.219l-2.066,1.896c-0.55-1.088-0.866-2.312-0.866-3.615 c0-4.465,3.619-8.084,8.084-8.084c4.464,0,8.083,3.619,8.083,8.084c0,4.464-3.619,8.083-8.083,8.083 c-1.145,0-2.228-0.247-3.213-0.678l-0.833,1.634c1.235,0.557,2.602,0.874,4.045,0.874c5.476,0,9.914-4.438,9.914-9.914 C22,6.523,17.562,2.085,12.086,2.085z"/>
-</g>
-</svg>
diff --git a/resources/oojs/images/icons/link.png b/resources/oojs/images/icons/link.png
deleted file mode 100644 (file)
index 7dfa268..0000000
Binary files a/resources/oojs/images/icons/link.png and /dev/null differ
diff --git a/resources/oojs/images/icons/link.svg b/resources/oojs/images/icons/link.svg
deleted file mode 100644 (file)
index dadf69c..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-<?xml version="1.0" encoding="iso-8859-1"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px"
-        height="24px" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
-<g id="link" style="opacity:0.75;">
-       <path id="right" d="M19.188,12.001c0,1.1-0.891,2.015-1.988,2.015l-4.195-0.015C13.543,15.089,13.968,16,15.002,16h3
-               C19.658,16,21,13.657,21,12s-1.342-4-2.998-4h-3c-1.034,0-1.459,0.911-1.998,1.999l4.195-0.015
-               C18.297,9.984,19.188,10.901,19.188,12.001z"/>
-       <path id="center" d="M8,12c0,0.535,0.42,1,0.938,1h6.109c0.518,0,0.938-0.465,0.938-1c0-0.534-0.42-1-0.938-1H8.938
-               C8.42,11,8,11.466,8,12z"/>
-       <path id="left" d="M4.816,11.999c0-1.1,0.891-2.015,1.988-2.015L11,9.999C10.461,8.911,10.036,8,9.002,8h-3
-               c-1.656,0-2.998,2.343-2.998,4s1.342,4,2.998,4h3c1.034,0,1.459-0.911,1.998-1.999l-4.195,0.015
-               C5.707,14.016,4.816,13.099,4.816,11.999z"/>
-</g>
-</svg>
diff --git a/resources/oojs/images/icons/menu.png b/resources/oojs/images/icons/menu.png
deleted file mode 100644 (file)
index b5ac60f..0000000
Binary files a/resources/oojs/images/icons/menu.png and /dev/null differ
diff --git a/resources/oojs/images/icons/menu.svg b/resources/oojs/images/icons/menu.svg
deleted file mode 100644 (file)
index 657fab2..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0" encoding="iso-8859-1"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px"
-        height="24px" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
-<g id="menu" style="opacity:0.75;">
-       <path id="lines" d="M6,15h12c0.553,0,1,0.447,1,1v1c0,0.553-0.447,1-1,1H6c-0.553,0-1-0.447-1-1v-1C5,15.447,5.447,15,6,15z M5,11v1
-               c0,0.553,0.447,1,1,1h12c0.553,0,1-0.447,1-1v-1c0-0.553-0.447-1-1-1H6C5.447,10,5,10.447,5,11z M5,6v1c0,0.553,0.447,1,1,1h12
-               c0.553,0,1-0.447,1-1V6c0-0.553-0.447-1-1-1H6C5.447,5,5,5.447,5,6z"/>
-</g>
-</svg>
diff --git a/resources/oojs/images/icons/move-ltr.png b/resources/oojs/images/icons/move-ltr.png
deleted file mode 100644 (file)
index ded5f05..0000000
Binary files a/resources/oojs/images/icons/move-ltr.png and /dev/null differ
diff --git a/resources/oojs/images/icons/move-ltr.svg b/resources/oojs/images/icons/move-ltr.svg
deleted file mode 100644 (file)
index a378a5d..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="iso-8859-1"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px"
-        height="24px" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
-<g id="move-ltr" style="opacity:0.75;">
-       <polygon id="arrow" style="fill-rule:evenodd;clip-rule:evenodd;" points="8.935,7.181 14.237,12.483 8.935,17.786
-               10.349,19.2 17.065,12.483 10.349,5.767"/>
-</g>
-</svg>
diff --git a/resources/oojs/images/icons/move-rtl.png b/resources/oojs/images/icons/move-rtl.png
deleted file mode 100644 (file)
index fc6e62d..0000000
Binary files a/resources/oojs/images/icons/move-rtl.png and /dev/null differ
diff --git a/resources/oojs/images/icons/move-rtl.svg b/resources/oojs/images/icons/move-rtl.svg
deleted file mode 100644 (file)
index c0b334b..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="iso-8859-1"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px"
-        height="24px" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
-<g id="move-rtl" style="opacity:0.75;">
-       <polygon id="arrow_9_" style="fill-rule:evenodd;clip-rule:evenodd;" points="15.065,17.786 9.763,12.483 15.065,7.181
-               13.651,5.767 6.935,12.483 13.651,19.2"/>
-</g>
-</svg>
diff --git a/resources/oojs/images/icons/picture.png b/resources/oojs/images/icons/picture.png
deleted file mode 100644 (file)
index faf8af9..0000000
Binary files a/resources/oojs/images/icons/picture.png and /dev/null differ
diff --git a/resources/oojs/images/icons/picture.svg b/resources/oojs/images/icons/picture.svg
deleted file mode 100644 (file)
index 078ce10..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="iso-8859-1"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px"
-        height="24px" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
-<g id="picture" style="opacity:0.75;">
-       <path id="frame" style="fill-rule:evenodd;clip-rule:evenodd;" d="M18,4H6C4,3.993,3,4.993,3,6.993L3.014,16C3,18,4,18.988,6,19h12
-               c2-0.012,2.994-1,3-3.006V6.993C20.994,4.993,20,3.993,18,4z M19,17H5V6h14V17z"/>
-       <polygon id="mountains" style="fill-rule:evenodd;clip-rule:evenodd;" points="6,13.5 9.5,10 11.828,12.312 10.516,13.406
-               11.391,14.438 15.5,11 18,13 18,16 6,16"/>
-       <polygon id="sky" style="fill-rule:evenodd;clip-rule:evenodd;" points="6,12 9.516,7.844 12.562,11.016 15.5,9 18,11 18,7 6,7"/>
-</g>
-</svg>
diff --git a/resources/oojs/images/icons/remove-item.png b/resources/oojs/images/icons/remove-item.png
deleted file mode 100644 (file)
index 2f11db3..0000000
Binary files a/resources/oojs/images/icons/remove-item.png and /dev/null differ
diff --git a/resources/oojs/images/icons/remove-item.svg b/resources/oojs/images/icons/remove-item.svg
deleted file mode 100644 (file)
index b95e7d3..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24" height="24" viewBox="0, 0, 24, 24">
-  <g id="remove-item">
-    <path d="M8,11 L16,11 L16,13 L8,13 z" fill="#000000"/>
-  </g>
-  <defs/>
-</svg>
diff --git a/resources/oojs/images/icons/remove.png b/resources/oojs/images/icons/remove.png
deleted file mode 100644 (file)
index d7e116c..0000000
Binary files a/resources/oojs/images/icons/remove.png and /dev/null differ
diff --git a/resources/oojs/images/icons/remove.svg b/resources/oojs/images/icons/remove.svg
deleted file mode 100644 (file)
index 17c8d39..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="iso-8859-1"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px"
-        height="24px" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
-<g id="remove" style="opacity:0.75;">
-       <path id="trash_can" style="fill-rule:evenodd;clip-rule:evenodd;" d="M12,10h-1v6h1V10z M10,10H9v6h1V10z M14,10h-1v6h1V10z
-                M14,6V5H9v1H6v3h1v7.966l1,1.031v-0.074V18h6.984L15,17.982v0.015l1-1.031V9h1V6H14z M15,17H8V9h7V17z M16,8H7V7h9V8z"/>
-</g>
-</svg>
diff --git a/resources/oojs/images/icons/search.png b/resources/oojs/images/icons/search.png
deleted file mode 100644 (file)
index df29792..0000000
Binary files a/resources/oojs/images/icons/search.png and /dev/null differ
diff --git a/resources/oojs/images/icons/search.svg b/resources/oojs/images/icons/search.svg
deleted file mode 100644 (file)
index 37feda4..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="iso-8859-1"?>
-<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px"
-        height="24px" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
-<g id="search" style="opacity:0.75;">
-       <path id="magnifying_glass" d="M16.021,15.96l-2.374-2.375c-0.048-0.047-0.105-0.079-0.169-0.099c0.403-0.566,0.643-1.26,0.643-2.009
-               C14.12,9.557,12.563,8,10.644,8c-1.921,0-3.478,1.557-3.478,3.478c0,1.92,1.557,3.477,3.478,3.477c0.749,0,1.442-0.239,2.01-0.643
-               c0.019,0.063,0.051,0.121,0.098,0.169l2.375,2.374c0.19,0.189,0.543,0.143,0.79-0.104S16.21,16.15,16.021,15.96z M10.644,13.69
-               c-1.221,0-2.213-0.991-2.213-2.213c0-1.221,0.992-2.213,2.213-2.213c1.222,0,2.213,0.992,2.213,2.213
-               C12.856,12.699,11.865,13.69,10.644,13.69z"/>
-</g>
-</svg>
diff --git a/resources/oojs/images/icons/settings.png b/resources/oojs/images/icons/settings.png
deleted file mode 100644 (file)
index b1b35e9..0000000
Binary files a/resources/oojs/images/icons/settings.png and /dev/null differ
diff --git a/resources/oojs/images/icons/settings.svg b/resources/oojs/images/icons/settings.svg
deleted file mode 100644 (file)
index 1464a79..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24" height="24" viewBox="0, 0, 24, 24">
-  <g id="settings" opacity="0.75">
-    <path d="M3,4 L6,4 L6,6 L3,6 z" fill="#000000"/>
-    <path d="M12,4 L21,4 L21,6 L12,6 z" fill="#000000"/>
-    <path d="M8,3 L10,3 C10.552,3 11,3.448 11,4 L11,6 C11,6.552 10.552,7 10,7 L8,7 C7.448,7 7,6.552 7,6 L7,4 C7,3.448 7.448,3 8,3 z" fill="#000000"/>
-    <path d="M3,11 L12,11 L12,13 L3,13 z" fill="#000000"/>
-    <path d="M18,11 L21,11 L21,13 L18,13 z" fill="#000000"/>
-    <path d="M14,10 L16,10 C16.552,10 17,10.448 17,11 L17,13 C17,13.552 16.552,14 16,14 L14,14 C13.448,14 13,13.552 13,13 L13,11 C13,10.448 13.448,10 14,10 z" fill="#000000"/>
-    <path d="M3,18 L9,18 L9,20 L3,20 z" fill="#000000"/>
-    <path d="M15,18 L21,18 L21,20 L15,20 z" fill="#000000"/>
-    <path d="M11,17 L13,17 C13.552,17 14,17.448 14,18 L14,20 C14,20.552 13.552,21 13,21 L11,21 C10.448,21 10,20.552 10,20 L10,18 C10,17.448 10.448,17 11,17 z" fill="#000000"/>
-  </g>
-  <defs/>
-</svg>
diff --git a/resources/oojs/images/icons/tag.png b/resources/oojs/images/icons/tag.png
deleted file mode 100644 (file)
index 722f4d7..0000000
Binary files a/resources/oojs/images/icons/tag.png and /dev/null differ
diff --git a/resources/oojs/images/icons/tag.svg b/resources/oojs/images/icons/tag.svg
deleted file mode 100644 (file)
index d21e5e3..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="iso-8859-1"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px"
-        height="24px" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
-<g id="tag" style="opacity:0.75;">
-       <path d="M18.748,11.717c0.389,0.389,0.389,1.025,0,1.414l-4.949,4.95c-0.389,0.389-1.025,0.389-1.414,0l-6.01-6.01
-               c-0.389-0.389-0.707-1.157-0.707-1.707L5.667,6c0-0.55,0.45-1,1-1h4.364c0.55,0,1.318,0.318,1.707,0.707L18.748,11.717z
-                M8.104,7.456C7.525,8.032,7.526,8.97,8.103,9.549c0.578,0.577,1.516,0.577,2.095,0.001c0.576-0.578,0.576-1.517,0-2.095
-               C9.617,6.879,8.68,6.878,8.104,7.456z"/>
-</g>
-</svg>
diff --git a/resources/oojs/images/icons/window.png b/resources/oojs/images/icons/window.png
deleted file mode 100644 (file)
index 3d48a3c..0000000
Binary files a/resources/oojs/images/icons/window.png and /dev/null differ
diff --git a/resources/oojs/images/icons/window.svg b/resources/oojs/images/icons/window.svg
deleted file mode 100644 (file)
index 621cf2c..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0" encoding="iso-8859-1"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px"
-        height="24px" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
-<g id="window" style="opacity:0.75;">
-       <rect id="title" x="7" y="10" width="10" height="1"/>
-       <path id="window" d="M16,19H8c-2.206,0-4-1.794-4-4V9c0-2.206,1.794-4,4-4h8c2.206,0,4,1.794,4,4v6C20,17.206,18.206,19,16,19z
-                M8,7C6.897,7,6,7.897,6,9v6c0,1.103,0.897,2,2,2h8c1.103,0,2-0.897,2-2V9c0-1.103-0.897-2-2-2H8z"/>
-</g>
-</svg>
diff --git a/resources/oojs/images/indicators/down.png b/resources/oojs/images/indicators/down.png
deleted file mode 100644 (file)
index 47ff54c..0000000
Binary files a/resources/oojs/images/indicators/down.png and /dev/null differ
diff --git a/resources/oojs/images/indicators/down.svg b/resources/oojs/images/indicators/down.svg
deleted file mode 100644 (file)
index c871f60..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="iso-8859-1"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="12px"
-        height="12px" viewBox="0 0 12 12" style="enable-background:new 0 0 12 12;" xml:space="preserve">
-<g id="down" style="opacity:0.75;">
-       <polygon id="arrow" style="fill-rule:evenodd;clip-rule:evenodd;" points="2.023,3 5.512,8.953 9,3"/>
-</g>
-</svg>
diff --git a/resources/oojs/images/indicators/required.png b/resources/oojs/images/indicators/required.png
deleted file mode 100644 (file)
index aeb35a3..0000000
Binary files a/resources/oojs/images/indicators/required.png and /dev/null differ
diff --git a/resources/oojs/images/indicators/required.svg b/resources/oojs/images/indicators/required.svg
deleted file mode 100644 (file)
index 7c60ec0..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="12" height="12" viewBox="0, 0, 12, 12">
-  <g id="required" opacity="0.75">
-    <path d="M7,0 L7,4.268 L10.696,2.134 L11.696,3.866 L8,6 L11.696,8.134 L10.696,9.866 L7,7.732 L7,12 L5,12 L5,7.732 L1.304,9.866 L0.304,8.134 L4,6 L0.304,3.866 L1.304,2.134 L5,4.268 L5,0 z" fill="#000000"/>
-  </g>
-  <defs/>
-</svg>
diff --git a/resources/oojs/images/indicators/up.png b/resources/oojs/images/indicators/up.png
deleted file mode 100644 (file)
index b827f6d..0000000
Binary files a/resources/oojs/images/indicators/up.png and /dev/null differ
diff --git a/resources/oojs/images/indicators/up.svg b/resources/oojs/images/indicators/up.svg
deleted file mode 100644 (file)
index a5d7f38..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="iso-8859-1"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="12px"
-        height="12px" viewBox="0 0 12 12" style="enable-background:new 0 0 12 12;" xml:space="preserve">
-<g id="up" style="opacity:0.75;">
-       <polygon id="arrow" style="fill-rule:evenodd;clip-rule:evenodd;" points="5.512,2.006 2,8 9.024,8                "/>
-</g>
-</svg>
diff --git a/resources/oojs/images/tail.svg b/resources/oojs/images/tail.svg
deleted file mode 100644 (file)
index 4df8bb2..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="iso-8859-1"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
-        width="15px" height="8px" viewBox="0 0 15 8" style="enable-background:new 0 0 15 8;" xml:space="preserve">
-<g id="tail">
-       <polygon id="outline" style="fill-rule:evenodd;clip-rule:evenodd;fill:#808080;" points="7.609,2.499 2.096,8 13.125,8"/>
-       <polygon id="fill" style="fill-rule:evenodd;clip-rule:evenodd;fill:#FFFFFF;" points="7.609,3 2.598,8 12.622,8"/>
-</g>
-</svg>
diff --git a/resources/oojs/images/textures/pending.gif b/resources/oojs/images/textures/pending.gif
deleted file mode 100644 (file)
index 1194eed..0000000
Binary files a/resources/oojs/images/textures/pending.gif and /dev/null differ
diff --git a/resources/oojs/images/textures/transparency.png b/resources/oojs/images/textures/transparency.png
deleted file mode 100644 (file)
index b8e36d3..0000000
Binary files a/resources/oojs/images/textures/transparency.png and /dev/null differ
diff --git a/resources/oojs/images/toolbar-shadow.png b/resources/oojs/images/toolbar-shadow.png
deleted file mode 100644 (file)
index 97e8d13..0000000
Binary files a/resources/oojs/images/toolbar-shadow.png and /dev/null differ
diff --git a/resources/oojs/oojs-ui.js b/resources/oojs/oojs-ui.js
deleted file mode 100644 (file)
index a58f65d..0000000
+++ /dev/null
@@ -1,7325 +0,0 @@
-/*!
- * OOjs UI v0.1.0-pre (a290673bbd)
- * https://www.mediawiki.org/wiki/OOjs_UI
- *
- * Copyright 2011–2014 OOjs Team and other contributors.
- * Released under the MIT license
- * http://oojs.mit-license.org
- *
- * Date: Wed Feb 12 2014 13:52:08 GMT-0800 (PST)
- */
-( function () {
-
-'use strict';
-/**
- * Namespace for all classes, static methods and static properties.
- *
- * @class
- * @singleton
- */
-OO.ui = {};
-
-OO.ui.bind = $.proxy;
-
-/**
- * Get the user's language and any fallback languages.
- *
- * These language codes are used to localize user interface elements in the user's language.
- *
- * In environments that provide a localization system, this function should be overridden to
- * return the user's language(s). The default implementation returns English (en) only.
- *
- * @returns {string[]} Language codes, in descending order of priority
- */
-OO.ui.getUserLanguages = function () {
-       return [ 'en' ];
-};
-
-/**
- * Get a value in an object keyed by language code.
- *
- * @param {Object.<string,Mixed>} obj Object keyed by language code
- * @param {string|null} [lang] Language code, if omitted or null defaults to any user language
- * @param {string} [fallback] Fallback code, used if no matching language can be found
- * @returns {Mixed} Local value
- */
-OO.ui.getLocalValue = function ( obj, lang, fallback ) {
-       var i, len, langs;
-
-       // Requested language
-       if ( obj[lang] ) {
-               return obj[lang];
-       }
-       // Known user language
-       langs = OO.ui.getUserLanguages();
-       for ( i = 0, len = langs.length; i < len; i++ ) {
-               lang = langs[i];
-               if ( obj[lang] ) {
-                       return obj[lang];
-               }
-       }
-       // Fallback language
-       if ( obj[fallback] ) {
-               return obj[fallback];
-       }
-       // First existing language
-       for ( lang in obj ) {
-               return obj[lang];
-       }
-
-       return undefined;
-};
-
-( function () {
-
-/**
- * Message store for the default implementation of OO.ui.msg
- *
- * Environments that provide a localization system should not use this, but should override
- * OO.ui.msg altogether.
- *
- * @private
- */
-var messages = {
-       // Label text for button to exit from dialog
-       'ooui-dialog-action-close': 'Close',
-       // Tool tip for a button that moves items in a list down one place
-       'ooui-outline-control-move-down': 'Move item down',
-       // Tool tip for a button that moves items in a list up one place
-       'ooui-outline-control-move-up': 'Move item up',
-       // Label for the toolbar group that contains a list of all other available tools
-       'ooui-toolbar-more': 'More'
-};
-
-/**
- * Get a localized message.
- *
- * In environments that provide a localization system, this function should be overridden to
- * return the message translated in the user's language. The default implementation always returns
- * English messages.
- *
- * After the message key, message parameters may optionally be passed. In the default implementation,
- * any occurrences of $1 are replaced with the first parameter, $2 with the second parameter, etc.
- * Alternative implementations of OO.ui.msg may use any substitution system they like, as long as
- * they support unnamed, ordered message parameters.
- *
- * @abstract
- * @param {string} key Message key
- * @param {Mixed...} [params] Message parameters
- * @returns {string} Translated message with parameters substituted
- */
-OO.ui.msg = function ( key ) {
-       var message = messages[key], params = Array.prototype.slice.call( arguments, 1 );
-       if ( typeof message === 'string' ) {
-               // Perform $1 substitution
-               message = message.replace( /\$(\d+)/g, function ( unused, n ) {
-                       var i = parseInt( n, 10 );
-                       return params[i - 1] !== undefined ? params[i - 1] : '$' + n;
-               } );
-       } else {
-               // Return placeholder if message not found
-               message = '[' + key + ']';
-       }
-       return message;
-};
-
-OO.ui.deferMsg = function ( key ) {
-       return function () {
-               return OO.ui.msg( key );
-       };
-};
-
-OO.ui.resolveMsg = function ( msg ) {
-       if ( $.isFunction( msg ) ) {
-               return msg();
-       }
-       return msg;
-};
-
-} )();
-
-// Add more as you need
-OO.ui.Keys = {
-       'UNDEFINED': 0,
-       'BACKSPACE': 8,
-       'DELETE': 46,
-       'LEFT': 37,
-       'RIGHT': 39,
-       'UP': 38,
-       'DOWN': 40,
-       'ENTER': 13,
-       'END': 35,
-       'HOME': 36,
-       'TAB': 9,
-       'PAGEUP': 33,
-       'PAGEDOWN': 34,
-       'ESCAPE': 27,
-       'SHIFT': 16,
-       'SPACE': 32
-};
-/**
- * DOM element abstraction.
- *
- * @class
- * @abstract
- *
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {Function} [$] jQuery for the frame the widget is in
- * @cfg {string[]} [classes] CSS class names
- * @cfg {jQuery} [$content] Content elements to append
- */
-OO.ui.Element = function OoUiElement( config ) {
-       // Configuration initialization
-       config = config || {};
-
-       // Properties
-       this.$ = config.$ || OO.ui.Element.getJQuery( document );
-       this.$element = this.$( this.$.context.createElement( this.getTagName() ) );
-
-       // Initialization
-       if ( Array.isArray( config.classes ) ) {
-               this.$element.addClass( config.classes.join( ' ' ) );
-       }
-       if ( config.$content ) {
-               this.$element.append( config.$content );
-       }
-};
-
-/* Static Properties */
-
-/**
- * @static
- * @property
- * @inheritable
- */
-OO.ui.Element.static = {};
-
-/**
- * HTML tag name.
- *
- * This may be ignored if getTagName is overridden.
- *
- * @static
- * @property {string}
- * @inheritable
- */
-OO.ui.Element.static.tagName = 'div';
-
-/* Static Methods */
-
-/**
- * Gets a jQuery function within a specific document.
- *
- * @static
- * @param {jQuery|HTMLElement|HTMLDocument|Window} context Context to bind the function to
- * @param {OO.ui.Frame} [frame] Frame of the document context
- * @returns {Function} Bound jQuery function
- */
-OO.ui.Element.getJQuery = function ( context, frame ) {
-       function wrapper( selector ) {
-               return $( selector, wrapper.context );
-       }
-
-       wrapper.context = this.getDocument( context );
-
-       if ( frame ) {
-               wrapper.frame = frame;
-       }
-
-       return wrapper;
-};
-
-/**
- * Get the document of an element.
- *
- * @static
- * @param {jQuery|HTMLElement|HTMLDocument|Window} obj Object to get the document for
- * @returns {HTMLDocument} Document object
- * @throws {Error} If context is invalid
- */
-OO.ui.Element.getDocument = function ( obj ) {
-       var doc =
-               // jQuery - selections created "offscreen" won't have a context, so .context isn't reliable
-               ( obj[0] && obj[0].ownerDocument ) ||
-               // Empty jQuery selections might have a context
-               obj.context ||
-               // HTMLElement
-               obj.ownerDocument ||
-               // Window
-               obj.document ||
-               // HTMLDocument
-               ( obj.nodeType === 9 && obj );
-
-       if ( doc ) {
-               return doc;
-       }
-
-       throw new Error( 'Invalid context' );
-};
-
-/**
- * Get the window of an element or document.
- *
- * @static
- * @param {jQuery|HTMLElement|HTMLDocument|Window} obj Context to get the window for
- * @returns {Window} Window object
- */
-OO.ui.Element.getWindow = function ( obj ) {
-       var doc = this.getDocument( obj );
-       return doc.parentWindow || doc.defaultView;
-};
-
-/**
- * Get the direction of an element or document.
- *
- * @static
- * @param {jQuery|HTMLElement|HTMLDocument|Window} obj Context to get the direction for
- * @returns {string} Text direction, either `ltr` or `rtl`
- */
-OO.ui.Element.getDir = function ( obj ) {
-       var isDoc, isWin;
-
-       if ( obj instanceof jQuery ) {
-               obj = obj[0];
-       }
-       isDoc = obj.nodeType === 9;
-       isWin = obj.document !== undefined;
-       if ( isDoc || isWin ) {
-               if ( isWin ) {
-                       obj = obj.document;
-               }
-               obj = obj.body;
-       }
-       return $( obj ).css( 'direction' );
-};
-
-/**
- * Get the offset between two frames.
- *
- * TODO: Make this function not use recursion.
- *
- * @static
- * @param {Window} from Window of the child frame
- * @param {Window} [to=window] Window of the parent frame
- * @param {Object} [offset] Offset to start with, used internally
- * @returns {Object} Offset object, containing left and top properties
- */
-OO.ui.Element.getFrameOffset = function ( from, to, offset ) {
-       var i, len, frames, frame, rect;
-
-       if ( !to ) {
-               to = window;
-       }
-       if ( !offset ) {
-               offset = { 'top': 0, 'left': 0 };
-       }
-       if ( from.parent === from ) {
-               return offset;
-       }
-
-       // Get iframe element
-       frames = from.parent.document.getElementsByTagName( 'iframe' );
-       for ( i = 0, len = frames.length; i < len; i++ ) {
-               if ( frames[i].contentWindow === from ) {
-                       frame = frames[i];
-                       break;
-               }
-       }
-
-       // Recursively accumulate offset values
-       if ( frame ) {
-               rect = frame.getBoundingClientRect();
-               offset.left += rect.left;
-               offset.top += rect.top;
-               if ( from !== to ) {
-                       this.getFrameOffset( from.parent, offset );
-               }
-       }
-       return offset;
-};
-
-/**
- * Get the offset between two elements.
- *
- * @static
- * @param {jQuery} $from
- * @param {jQuery} $to
- * @returns {Object} Translated position coordinates, containing top and left properties
- */
-OO.ui.Element.getRelativePosition = function ( $from, $to ) {
-       var from = $from.offset(),
-               to = $to.offset();
-       return { 'top': Math.round( from.top - to.top ), 'left': Math.round( from.left - to.left ) };
-};
-
-/**
- * Get element border sizes.
- *
- * @static
- * @param {HTMLElement} el Element to measure
- * @return {Object} Dimensions object with `top`, `left`, `bottom` and `right` properties
- */
-OO.ui.Element.getBorders = function ( el ) {
-       var doc = el.ownerDocument,
-               win = doc.parentWindow || doc.defaultView,
-               style = win && win.getComputedStyle ?
-                       win.getComputedStyle( el, null ) :
-                       el.currentStyle,
-               $el = $( el ),
-               top = parseFloat( style ? style.borderTopWidth : $el.css( 'borderTopWidth' ) ) || 0,
-               left = parseFloat( style ? style.borderLeftWidth : $el.css( 'borderLeftWidth' ) ) || 0,
-               bottom = parseFloat( style ? style.borderBottomWidth : $el.css( 'borderBottomWidth' ) ) || 0,
-               right = parseFloat( style ? style.borderRightWidth : $el.css( 'borderRightWidth' ) ) || 0;
-
-       return {
-               'top': Math.round( top ),
-               'left': Math.round( left ),
-               'bottom': Math.round( bottom ),
-               'right': Math.round( right )
-       };
-};
-
-/**
- * Get dimensions of an element or window.
- *
- * @static
- * @param {HTMLElement|Window} el Element to measure
- * @return {Object} Dimensions object with `borders`, `scroll`, `scrollbar` and `rect` properties
- */
-OO.ui.Element.getDimensions = function ( el ) {
-       var $el, $win,
-               doc = el.ownerDocument || el.document,
-               win = doc.parentWindow || doc.defaultView;
-
-       if ( win === el || el === doc.documentElement ) {
-               $win = $( win );
-               return {
-                       'borders': { 'top': 0, 'left': 0, 'bottom': 0, 'right': 0 },
-                       'scroll': {
-                               'top': $win.scrollTop(),
-                               'left': $win.scrollLeft()
-                       },
-                       'scrollbar': { 'right': 0, 'bottom': 0 },
-                       'rect': {
-                               'top': 0,
-                               'left': 0,
-                               'bottom': $win.innerHeight(),
-                               'right': $win.innerWidth()
-                       }
-               };
-       } else {
-               $el = $( el );
-               return {
-                       'borders': this.getBorders( el ),
-                       'scroll': {
-                               'top': $el.scrollTop(),
-                               'left': $el.scrollLeft()
-                       },
-                       'scrollbar': {
-                               'right': $el.innerWidth() - el.clientWidth,
-                               'bottom': $el.innerHeight() - el.clientHeight
-                       },
-                       'rect': el.getBoundingClientRect()
-               };
-       }
-};
-
-/**
- * Get closest scrollable container.
- *
- * Traverses up until either a scrollable element or the root is reached, in which case the window
- * will be returned.
- *
- * @static
- * @param {HTMLElement} el Element to find scrollable container for
- * @param {string} [dimension] Dimension of scrolling to look for; `x`, `y` or omit for either
- * @return {HTMLElement|Window} Closest scrollable container
- */
-OO.ui.Element.getClosestScrollableContainer = function ( el, dimension ) {
-       var i, val,
-               props = [ 'overflow' ],
-               $parent = $( el ).parent();
-
-       if ( dimension === 'x' || dimension === 'y' ) {
-               props.push( 'overflow-' + dimension );
-       }
-
-       while ( $parent.length ) {
-               if ( $parent[0] === el.ownerDocument.body ) {
-                       return $parent[0];
-               }
-               i = props.length;
-               while ( i-- ) {
-                       val = $parent.css( props[i] );
-                       if ( val === 'auto' || val === 'scroll' ) {
-                               return $parent[0];
-                       }
-               }
-               $parent = $parent.parent();
-       }
-       return this.getDocument( el ).body;
-};
-
-/**
- * Scroll element into view
- *
- * @static
- * @param {HTMLElement} el Element to scroll into view
- * @param {Object} [config={}] Configuration config
- * @param {string} [config.duration] jQuery animation duration value
- * @param {string} [config.direction] Scroll in only one direction, e.g. 'x' or 'y', omit
- *  to scroll in both directions
- * @param {Function} [config.complete] Function to call when scrolling completes
- */
-OO.ui.Element.scrollIntoView = function ( el, config ) {
-       // Configuration initialization
-       config = config || {};
-
-       var anim = {},
-               callback = typeof config.complete === 'function' && config.complete,
-               sc = this.getClosestScrollableContainer( el, config.direction ),
-               $sc = $( sc ),
-               eld = this.getDimensions( el ),
-               scd = this.getDimensions( sc ),
-               rel = {
-                       'top': eld.rect.top - ( scd.rect.top + scd.borders.top ),
-                       'bottom': scd.rect.bottom - scd.borders.bottom - scd.scrollbar.bottom - eld.rect.bottom,
-                       'left': eld.rect.left - ( scd.rect.left + scd.borders.left ),
-                       'right': scd.rect.right - scd.borders.right - scd.scrollbar.right - eld.rect.right
-               };
-
-       if ( !config.direction || config.direction === 'y' ) {
-               if ( rel.top < 0 ) {
-                       anim.scrollTop = scd.scroll.top + rel.top;
-               } else if ( rel.top > 0 && rel.bottom < 0 ) {
-                       anim.scrollTop = scd.scroll.top + Math.min( rel.top, -rel.bottom );
-               }
-       }
-       if ( !config.direction || config.direction === 'x' ) {
-               if ( rel.left < 0 ) {
-                       anim.scrollLeft = scd.scroll.left + rel.left;
-               } else if ( rel.left > 0 && rel.right < 0 ) {
-                       anim.scrollLeft = scd.scroll.left + Math.min( rel.left, -rel.right );
-               }
-       }
-       if ( !$.isEmptyObject( anim ) ) {
-               $sc.stop( true ).animate( anim, config.duration || 'fast' );
-               if ( callback ) {
-                       $sc.queue( function ( next ) {
-                               callback();
-                               next();
-                       } );
-               }
-       } else {
-               if ( callback ) {
-                       callback();
-               }
-       }
-};
-
-/* Methods */
-
-/**
- * Get the HTML tag name.
- *
- * Override this method to base the result on instance information.
- *
- * @returns {string} HTML tag name
- */
-OO.ui.Element.prototype.getTagName = function () {
-       return this.constructor.static.tagName;
-};
-
-/**
- * Get the DOM document.
- *
- * @returns {HTMLDocument} Document object
- */
-OO.ui.Element.prototype.getElementDocument = function () {
-       return OO.ui.Element.getDocument( this.$element );
-};
-
-/**
- * Get the DOM window.
- *
- * @returns {Window} Window object
- */
-OO.ui.Element.prototype.getElementWindow = function () {
-       return OO.ui.Element.getWindow( this.$element );
-};
-
-/**
- * Get closest scrollable container.
- *
- * @method
- * @see #static-method-getClosestScrollableContainer
- */
-OO.ui.Element.prototype.getClosestScrollableElementContainer = function () {
-       return OO.ui.Element.getClosestScrollableContainer( this.$element[0] );
-};
-
-/**
- * Scroll element into view
- *
- * @method
- * @see #static-method-scrollIntoView
- * @param {Object} [config={}]
- */
-OO.ui.Element.prototype.scrollElementIntoView = function ( config ) {
-       return OO.ui.Element.scrollIntoView( this.$element[0], config );
-};
-
-( function () {
-       // Static
-       var specialFocusin;
-
-       function handler( e ) {
-               jQuery.event.simulate( 'focusin', e.target, jQuery.event.fix( e ), /* bubble = */ true );
-       }
-
-       specialFocusin = {
-               setup: function () {
-                       var doc = this.ownerDocument || this,
-                               attaches = $.data( doc, 'ooui-focusin-attaches' );
-                       if ( !attaches ) {
-                               doc.addEventListener( 'focus', handler, true );
-                       }
-                       $.data( doc, 'ooui-focusin-attaches', ( attaches || 0 ) + 1 );
-               },
-               teardown: function () {
-                       var doc = this.ownerDocument || this,
-                               attaches = $.data( doc, 'ooui-focusin-attaches' ) - 1;
-                       if ( !attaches ) {
-                               doc.removeEventListener( 'focus', handler, true );
-                               $.removeData( doc, 'ooui-focusin-attaches' );
-                       } else {
-                               $.data( doc, 'ooui-focusin-attaches', attaches );
-                       }
-               }
-       };
-
-       /**
-        * Bind a handler for an event on the DOM element.
-        *
-        * Uses jQuery internally for everything except for events which are
-        * known to have issues in the browser or in jQuery. This method
-        * should become obsolete eventually.
-        *
-        * @param {string} event
-        * @param {Function} callback
-        */
-       OO.ui.Element.prototype.onDOMEvent = function ( event, callback ) {
-               var orig;
-
-               if ( event === 'focusin' ) {
-                       // jQuery 1.8.3 has a bug with handling focusin events inside iframes.
-                       // Firefox doesn't support focusin at all, so we listen for 'focus' on the
-                       // document, and simulate a 'focusin' event on the target element and make
-                       // it bubble from there.
-                       //
-                       // - http://jsfiddle.net/sw3hr/
-                       // - http://bugs.jquery.com/ticket/14180
-                       // - https://github.com/jquery/jquery/commit/1cecf64e5aa4153
-
-                       // Replace jQuery's override with our own
-                       orig = $.event.special.focusin;
-                       $.event.special.focusin = specialFocusin;
-
-                       this.$element.on( event, callback );
-
-                       // Restore
-                       $.event.special.focusin = orig;
-
-               } else {
-                       this.$element.on( event, callback );
-               }
-       };
-
-       /**
-        * @param {string} event
-        * @param {Function} callback
-        */
-       OO.ui.Element.prototype.offDOMEvent = function ( event, callback ) {
-               var orig;
-               if ( event === 'focusin' ) {
-                       orig = $.event.special.focusin;
-                       $.event.special.focusin = specialFocusin;
-                       this.$element.off( event, callback );
-                       $.event.special.focusin = orig;
-               } else {
-                       this.$element.off( event, callback );
-               }
-       };
-}() );
-/**
- * Embedded iframe with the same styles as its parent.
- *
- * @class
- * @extends OO.ui.Element
- * @mixins OO.EventEmitter
- *
- * @constructor
- * @param {Object} [config] Configuration options
- */
-OO.ui.Frame = function OoUiFrame( config ) {
-       // Parent constructor
-       OO.ui.Element.call( this, config );
-
-       // Mixin constructors
-       OO.EventEmitter.call( this );
-
-       // Properties
-       this.initialized = false;
-       this.config = config;
-
-       // Initialize
-       this.$element
-               .addClass( 'oo-ui-frame' )
-               .attr( { 'frameborder': 0, 'scrolling': 'no' } );
-
-};
-
-/* Inheritance */
-
-OO.inheritClass( OO.ui.Frame, OO.ui.Element );
-
-OO.mixinClass( OO.ui.Frame, OO.EventEmitter );
-
-/* Static Properties */
-
-OO.ui.Frame.static.tagName = 'iframe';
-
-/* Events */
-
-/**
- * @event initialize
- */
-
-/* Static Methods */
-
-/**
- * Transplant the CSS styles from as parent document to a frame's document.
- *
- * This loops over the style sheets in the parent document, and copies their nodes to the
- * frame's document. It then polls the document to see when all styles have loaded, and once they
- * have, invokes the callback.
- *
- * If the styles still haven't loaded after a long time (5 seconds by default), we give up waiting
- * and invoke the callback anyway. This protects against cases like a display: none; iframe in
- * Firefox, where the styles won't load until the iframe becomes visible.
- *
- * For details of how we arrived at the strategy used in this function, see #load.
- *
- * @static
- * @method
- * @inheritable
- * @param {HTMLDocument} parentDoc Document to transplant styles from
- * @param {HTMLDocument} frameDoc Document to transplant styles to
- * @param {Function} [callback] Callback to execute once styles have loaded
- * @param {number} [timeout=5000] How long to wait before giving up (in ms). If 0, never give up.
- */
-OO.ui.Frame.static.transplantStyles = function ( parentDoc, frameDoc, callback, timeout ) {
-       var i, numSheets, styleNode, newNode, timeoutID, pollNodeId, $pendingPollNodes,
-               $pollNodes = $( [] ),
-               // Fake font-family value
-               fontFamily = 'oo-ui-frame-transplantStyles-loaded';
-
-       for ( i = 0, numSheets = parentDoc.styleSheets.length; i < numSheets; i++ ) {
-               styleNode = parentDoc.styleSheets[i].ownerNode;
-               if ( callback && styleNode.nodeName.toLowerCase() === 'link' ) {
-                       // External stylesheet
-                       // Create a node with a unique ID that we're going to monitor to see when the CSS
-                       // has loaded
-                       pollNodeId = 'oo-ui-frame-transplantStyles-loaded-' + i;
-                       $pollNodes = $pollNodes.add( $( '<div>', frameDoc )
-                               .attr( 'id', pollNodeId )
-                               .appendTo( frameDoc.body )
-                       );
-
-                       // Add <style>@import url(...); #pollNodeId { font-family: ... }</style>
-                       // The font-family rule will only take effect once the @import finishes
-                       newNode = frameDoc.createElement( 'style' );
-                       newNode.textContent = '@import url(' + styleNode.href + ');\n' +
-                               '#' + pollNodeId + ' { font-family: ' + fontFamily + '; }';
-               } else {
-                       // Not an external stylesheet, or no polling required; just copy the node over
-                       newNode = frameDoc.importNode( styleNode, true );
-               }
-               frameDoc.head.appendChild( newNode );
-       }
-
-       if ( callback ) {
-               // Poll every 100ms until all external stylesheets have loaded
-               $pendingPollNodes = $pollNodes;
-               timeoutID = setTimeout( function pollExternalStylesheets() {
-                       while (
-                               $pendingPollNodes.length > 0 &&
-                               $pendingPollNodes.eq( 0 ).css( 'font-family' ) === fontFamily
-                       ) {
-                               $pendingPollNodes = $pendingPollNodes.slice( 1 );
-                       }
-
-                       if ( $pendingPollNodes.length === 0 ) {
-                               // We're done!
-                               if ( timeoutID !== null ) {
-                                       timeoutID = null;
-                                       $pollNodes.remove();
-                                       callback();
-                               }
-                       } else {
-                               timeoutID = setTimeout( pollExternalStylesheets, 100 );
-                       }
-               }, 100 );
-               // ...but give up after a while
-               if ( timeout !== 0 ) {
-                       setTimeout( function () {
-                               if ( timeoutID ) {
-                                       clearTimeout( timeoutID );
-                                       timeoutID = null;
-                                       $pollNodes.remove();
-                                       callback();
-                               }
-                       }, timeout || 5000 );
-               }
-       }
-};
-
-/* Methods */
-
-/**
- * Load the frame contents.
- *
- * Once the iframe's stylesheets are loaded, the `initialize` event will be emitted.
- *
- * Sounds simple right? Read on...
- *
- * When you create a dynamic iframe using open/write/close, the window.load event for the
- * iframe is triggered when you call close, and there's no further load event to indicate that
- * everything is actually loaded.
- *
- * In Chrome, stylesheets don't show up in document.styleSheets until they have loaded, so we could
- * just poll that array and wait for it to have the right length. However, in Firefox, stylesheets
- * are added to document.styleSheets immediately, and the only way you can determine whether they've
- * loaded is to attempt to access .cssRules and wait for that to stop throwing an exception. But
- * cross-domain stylesheets never allow .cssRules to be accessed even after they have loaded.
- *
- * The workaround is to change all `<link href="...">` tags to `<style>@import url(...)</style>` tags.
- * Because `@import` is blocking, Chrome won't add the stylesheet to document.styleSheets until
- * the `@import` has finished, and Firefox won't allow .cssRules to be accessed until the `@import`
- * has finished. And because the contents of the `<style>` tag are from the same origin, accessing
- * .cssRules is allowed.
- *
- * However, now that we control the styles we're injecting, we might as well do away with
- * browser-specific polling hacks like document.styleSheets and .cssRules, and instead inject
- * `<style>@import url(...); #foo { font-family: someValue; }</style>`, then create `<div id="foo">`
- * and wait for its font-family to change to someValue. Because `@import` is blocking, the font-family
- * rule is not applied until after the `@import` finishes.
- *
- * All this stylesheet injection and polling magic is in #transplantStyles.
- *
- * @fires initialize
- */
-OO.ui.Frame.prototype.load = function () {
-       var win = this.$element.prop( 'contentWindow' ),
-               doc = win.document,
-               frame = this;
-
-       // Figure out directionality:
-       this.dir = this.$element.closest( '[dir]' ).prop( 'dir' ) || 'ltr';
-
-       // Initialize contents
-       doc.open();
-       doc.write(
-               '<!doctype html>' +
-               '<html>' +
-                       '<body class="oo-ui-frame-body oo-ui-' + this.dir + '" style="direction:' + this.dir + ';" dir="' + this.dir + '">' +
-                               '<div class="oo-ui-frame-content"></div>' +
-                       '</body>' +
-               '</html>'
-       );
-       doc.close();
-
-       // Properties
-       this.$ = OO.ui.Element.getJQuery( doc, this );
-       this.$content = this.$( '.oo-ui-frame-content' );
-       this.$document = this.$( doc );
-
-       this.constructor.static.transplantStyles( this.getElementDocument(), this.$document[0],
-               function () {
-                       frame.initialized = true;
-                       frame.emit( 'initialize' );
-               }
-       );
-};
-
-/**
- * Run a callback as soon as the frame has been initialized.
- *
- * @param {Function} callback
- */
-OO.ui.Frame.prototype.run = function ( callback ) {
-       if ( this.initialized ) {
-               callback();
-       } else {
-               this.once( 'initialize', callback );
-       }
-};
-
-/**
- * Sets the size of the frame.
- *
- * @method
- * @param {number} width Frame width in pixels
- * @param {number} height Frame height in pixels
- * @chainable
- */
-OO.ui.Frame.prototype.setSize = function ( width, height ) {
-       this.$element.css( { 'width': width, 'height': height } );
-       return this;
-};
-/**
- * Container for elements in a child frame.
- *
- * There are two ways to specify a title: set the static `title` property or provide a `title`
- * property in the configuration options. The latter will override the former.
- *
- * @class
- * @abstract
- * @extends OO.ui.Element
- * @mixins OO.EventEmitter
- *
- * @constructor
- * @param {OO.ui.WindowSet} windowSet Window set this dialog is part of
- * @param {Object} [config] Configuration options
- * @cfg {string|Function} [title] Title string or function that returns a string
- * @cfg {string} [icon] Symbolic name of icon
- * @fires initialize
- */
-OO.ui.Window = function OoUiWindow( windowSet, config ) {
-       // Parent constructor
-       OO.ui.Element.call( this, config );
-
-       // Mixin constructors
-       OO.EventEmitter.call( this );
-
-       // Properties
-       this.windowSet = windowSet;
-       this.visible = false;
-       this.opening = false;
-       this.closing = false;
-       this.title = OO.ui.resolveMsg( config.title || this.constructor.static.title );
-       this.icon = config.icon || this.constructor.static.icon;
-       this.frame = new OO.ui.Frame( { '$': this.$ } );
-       this.$frame = this.$( '<div>' );
-       this.$ = function () {
-               throw new Error( 'this.$() cannot be used until the frame has been initialized.' );
-       };
-
-       // Initialization
-       this.$element
-               .addClass( 'oo-ui-window' )
-               // Hide the window using visibility: hidden; while the iframe is still loading
-               // Can't use display: none; because that prevents the iframe from loading in Firefox
-               .css( 'visibility', 'hidden' )
-               .append( this.$frame );
-       this.$frame
-               .addClass( 'oo-ui-window-frame' )
-               .append( this.frame.$element );
-
-       // Events
-       this.frame.connect( this, { 'initialize': 'initialize' } );
-};
-
-/* Inheritance */
-
-OO.inheritClass( OO.ui.Window, OO.ui.Element );
-
-OO.mixinClass( OO.ui.Window, OO.EventEmitter );
-
-/* Events */
-
-/**
- * Initialize contents.
- *
- * Fired asynchronously after construction when iframe is ready.
- *
- * @event initialize
- */
-
-/**
- * Open window.
- *
- * Fired after window has been opened.
- *
- * @event open
- * @param {Object} data Window opening data
- */
-
-/**
- * Close window.
- *
- * Fired after window has been closed.
- *
- * @event close
- * @param {Object} data Window closing data
- */
-
-/* Static Properties */
-
-/**
- * Symbolic name of icon.
- *
- * @static
- * @inheritable
- * @property {string}
- */
-OO.ui.Window.static.icon = 'window';
-
-/**
- * Window title.
- *
- * @static
- * @inheritable
- * @property {string|Function} Title string or function that returns a string
- */
-OO.ui.Window.static.title = null;
-
-/* Methods */
-
-/**
- * Check if window is visible.
- *
- * @method
- * @returns {boolean} Window is visible
- */
-OO.ui.Window.prototype.isVisible = function () {
-       return this.visible;
-};
-
-/**
- * Check if window is opening.
- *
- * @method
- * @returns {boolean} Window is opening
- */
-OO.ui.Window.prototype.isOpening = function () {
-       return this.opening;
-};
-
-/**
- * Check if window is closing.
- *
- * @method
- * @returns {boolean} Window is closing
- */
-OO.ui.Window.prototype.isClosing = function () {
-       return this.closing;
-};
-
-/**
- * Get the window frame.
- *
- * @method
- * @returns {OO.ui.Frame} Frame of window
- */
-OO.ui.Window.prototype.getFrame = function () {
-       return this.frame;
-};
-
-/**
- * Get the window set.
- *
- * @method
- * @returns {OO.ui.WindowSet} Window set
- */
-OO.ui.Window.prototype.getWindowSet = function () {
-       return this.windowSet;
-};
-
-/**
- * Get the window title.
- *
- * @returns {string} Title text
- */
-OO.ui.Window.prototype.getTitle = function () {
-       return this.title;
-};
-
-/**
- * Get the window icon.
- *
- * @returns {string} Symbolic name of icon
- */
-OO.ui.Window.prototype.getIcon = function () {
-       return this.icon;
-};
-
-/**
- * Set the size of window frame.
- *
- * @param {number} [width=auto] Custom width
- * @param {number} [height=auto] Custom height
- * @chainable
- */
-OO.ui.Window.prototype.setSize = function ( width, height ) {
-       if ( !this.frame.$content ) {
-               return;
-       }
-
-       this.frame.$element.css( {
-               'width': width === undefined ? 'auto' : width,
-               'height': height === undefined ? 'auto' : height
-       } );
-
-       return this;
-};
-
-/**
- * Set the title of the window.
- *
- * @param {string|Function} title Title text or a function that returns text
- * @chainable
- */
-OO.ui.Window.prototype.setTitle = function ( title ) {
-       this.title = OO.ui.resolveMsg( title );
-       if ( this.$title ) {
-               this.$title.text( title );
-       }
-       return this;
-};
-
-/**
- * Set the icon of the window.
- *
- * @param {string} icon Symbolic name of icon
- * @chainable
- */
-OO.ui.Window.prototype.setIcon = function ( icon ) {
-       if ( this.$icon ) {
-               this.$icon.removeClass( 'oo-ui-icon-' + this.icon );
-       }
-       this.icon = icon;
-       if ( this.$icon ) {
-               this.$icon.addClass( 'oo-ui-icon-' + this.icon );
-       }
-
-       return this;
-};
-
-/**
- * Set the position of window to fit with contents..
- *
- * @param {string} left Left offset
- * @param {string} top Top offset
- * @chainable
- */
-OO.ui.Window.prototype.setPosition = function ( left, top ) {
-       this.$element.css( { 'left': left, 'top': top } );
-       return this;
-};
-
-/**
- * Set the height of window to fit with contents.
- *
- * @param {number} [min=0] Min height
- * @param {number} [max] Max height (defaults to content's outer height)
- * @chainable
- */
-OO.ui.Window.prototype.fitHeightToContents = function ( min, max ) {
-       var height = this.frame.$content.outerHeight();
-
-       this.frame.$element.css(
-               'height', Math.max( min || 0, max === undefined ? height : Math.min( max, height ) )
-       );
-
-       return this;
-};
-
-/**
- * Set the width of window to fit with contents.
- *
- * @param {number} [min=0] Min height
- * @param {number} [max] Max height (defaults to content's outer width)
- * @chainable
- */
-OO.ui.Window.prototype.fitWidthToContents = function ( min, max ) {
-       var width = this.frame.$content.outerWidth();
-
-       this.frame.$element.css(
-               'width', Math.max( min || 0, max === undefined ? width : Math.min( max, width ) )
-       );
-
-       return this;
-};
-
-/**
- * Initialize window contents.
- *
- * The first time the window is opened, #initialize is called when it's safe to begin populating
- * its contents. See #setup for a way to make changes each time the window opens.
- *
- * Once this method is called, this.$$ can be used to create elements within the frame.
- *
- * @method
- * @fires initialize
- * @chainable
- */
-OO.ui.Window.prototype.initialize = function () {
-       // Properties
-       this.$ = this.frame.$;
-       this.$title = this.$( '<div class="oo-ui-window-title"></div>' )
-               .text( this.title );
-       this.$icon = this.$( '<div class="oo-ui-window-icon"></div>' )
-               .addClass( 'oo-ui-icon-' + this.icon );
-       this.$head = this.$( '<div class="oo-ui-window-head"></div>' );
-       this.$body = this.$( '<div class="oo-ui-window-body"></div>' );
-       this.$foot = this.$( '<div class="oo-ui-window-foot"></div>' );
-       this.$overlay = this.$( '<div class="oo-ui-window-overlay"></div>' );
-
-       // Initialization
-       this.frame.$content.append(
-               this.$head.append( this.$icon, this.$title ),
-               this.$body,
-               this.$foot,
-               this.$overlay
-       );
-
-       // Undo the visibility: hidden; hack from the constructor and apply display: none;
-       // We can do this safely now that the iframe has initialized
-       this.$element.hide().css( 'visibility', '' );
-
-       this.emit( 'initialize' );
-
-       return this;
-};
-
-/**
- * Setup window for use.
- *
- * Each time the window is opened, once it's ready to be interacted with, this will set it up for
- * use in a particular context, based on the `data` argument.
- *
- * When you override this method, you must call the parent method at the very beginning.
- *
- * @method
- * @abstract
- * @param {Object} [data] Window opening data
- */
-OO.ui.Window.prototype.setup = function () {
-       // Override to do something
-};
-
-/**
- * Tear down window after use.
- *
- * Each time the window is closed, and it's done being interacted with, this will tear it down and
- * do something with the user's interactions within the window, based on the `data` argument.
- *
- * When you override this method, you must call the parent method at the very end.
- *
- * @method
- * @abstract
- * @param {Object} [data] Window closing data
- */
-OO.ui.Window.prototype.teardown = function () {
-       // Override to do something
-};
-
-/**
- * Open window.
- *
- * Do not override this method. See #setup for a way to make changes each time the window opens.
- *
- * @method
- * @param {Object} [data] Window opening data
- * @fires open
- * @chainable
- */
-OO.ui.Window.prototype.open = function ( data ) {
-       if ( !this.opening && !this.closing && !this.visible ) {
-               this.opening = true;
-               this.frame.run( OO.ui.bind( function () {
-                       this.$element.show();
-                       this.visible = true;
-                       this.frame.$element.focus();
-                       this.emit( 'opening', data );
-                       this.setup( data );
-                       this.emit( 'open', data );
-                       this.opening = false;
-               }, this ) );
-       }
-
-       return this;
-};
-
-/**
- * Close window.
- *
- * See #teardown for a way to do something each time the window closes.
- *
- * @method
- * @param {Object} [data] Window closing data
- * @fires close
- * @chainable
- */
-OO.ui.Window.prototype.close = function ( data ) {
-       if ( !this.opening && !this.closing && this.visible ) {
-               this.frame.$content.find( ':focus' ).blur();
-               this.closing = true;
-               this.$element.hide();
-               this.visible = false;
-               this.emit( 'closing', data );
-               this.teardown( data );
-               this.emit( 'close', data );
-               this.closing = false;
-       }
-
-       return this;
-};
-/**
- * Set of mutually exclusive windows.
- *
- * @class
- * @extends OO.ui.Element
- * @mixins OO.EventEmitter
- *
- * @constructor
- * @param {OO.Factory} factory Window factory
- * @param {Object} [config] Configuration options
- */
-OO.ui.WindowSet = function OoUiWindowSet( factory, config ) {
-       // Parent constructor
-       OO.ui.Element.call( this, config );
-
-       // Mixin constructors
-       OO.EventEmitter.call( this );
-
-       // Properties
-       this.factory = factory;
-       this.windows = {};
-       this.currentWindow = null;
-
-       // Initialization
-       this.$element.addClass( 'oo-ui-windowSet' );
-};
-
-/* Inheritance */
-
-OO.inheritClass( OO.ui.WindowSet, OO.ui.Element );
-
-OO.mixinClass( OO.ui.WindowSet, OO.EventEmitter );
-
-/* Events */
-
-/**
- * @event opening
- * @param {OO.ui.Window} win Window that's being opened
- * @param {Object} config Window opening information
- */
-
-/**
- * @event open
- * @param {OO.ui.Window} win Window that's been opened
- * @param {Object} config Window opening information
- */
-
-/**
- * @event closing
- * @param {OO.ui.Window} win Window that's being closed
- * @param {Object} config Window closing information
- */
-
-/**
- * @event close
- * @param {OO.ui.Window} win Window that's been closed
- * @param {Object} config Window closing information
- */
-
-/* Methods */
-
-/**
- * Handle a window that's being opened.
- *
- * @method
- * @param {OO.ui.Window} win Window that's being opened
- * @param {Object} [config] Window opening information
- * @fires opening
- */
-OO.ui.WindowSet.prototype.onWindowOpening = function ( win, config ) {
-       if ( this.currentWindow && this.currentWindow !== win ) {
-               this.currentWindow.close();
-       }
-       this.currentWindow = win;
-       this.emit( 'opening', win, config );
-};
-
-/**
- * Handle a window that's been opened.
- *
- * @method
- * @param {OO.ui.Window} win Window that's been opened
- * @param {Object} [config] Window opening information
- * @fires open
- */
-OO.ui.WindowSet.prototype.onWindowOpen = function ( win, config ) {
-       this.emit( 'open', win, config );
-};
-
-/**
- * Handle a window that's being closed.
- *
- * @method
- * @param {OO.ui.Window} win Window that's being closed
- * @param {Object} [config] Window closing information
- * @fires closing
- */
-OO.ui.WindowSet.prototype.onWindowClosing = function ( win, config ) {
-       this.currentWindow = null;
-       this.emit( 'closing', win, config );
-};
-
-/**
- * Handle a window that's been closed.
- *
- * @method
- * @param {OO.ui.Window} win Window that's been closed
- * @param {Object} [config] Window closing information
- * @fires close
- */
-OO.ui.WindowSet.prototype.onWindowClose = function ( win, config ) {
-       this.emit( 'close', win, config );
-};
-
-/**
- * Get the current window.
- *
- * @method
- * @returns {OO.ui.Window} Current window
- */
-OO.ui.WindowSet.prototype.getCurrentWindow = function () {
-       return this.currentWindow;
-};
-
-/**
- * Return a given window.
- *
- * @param {string} name Symbolic name of window
- * @return {OO.ui.Window} Window with specified name
- */
-OO.ui.WindowSet.prototype.getWindow = function ( name ) {
-       var win;
-
-       if ( !this.factory.lookup( name ) ) {
-               throw new Error( 'Unknown window: ' + name );
-       }
-       if ( !( name in this.windows ) ) {
-               win = this.windows[name] = this.factory.create( name, this, { '$': this.$ } );
-               win.connect( this, {
-                       'opening': [ 'onWindowOpening', win ],
-                       'open': [ 'onWindowOpen', win ],
-                       'closing': [ 'onWindowClosing', win ],
-                       'close': [ 'onWindowClose', win ]
-               } );
-               this.$element.append( win.$element );
-               win.getFrame().load();
-       }
-       return this.windows[name];
-};
-/**
- * Modal dialog box.
- *
- * @class
- * @abstract
- * @extends OO.ui.Window
- *
- * @constructor
- * @param {OO.ui.WindowSet} windowSet Window set this dialog is part of
- * @param {Object} [config] Configuration options
- * @cfg {boolean} [footless] Hide foot
- * @cfg {boolean} [small] Make the dialog small
- */
-OO.ui.Dialog = function OoUiDialog( windowSet, config ) {
-       // Configuration initialization
-       config = config || {};
-
-       // Parent constructor
-       OO.ui.Window.call( this, windowSet, config );
-
-       // Properties
-       this.visible = false;
-       this.footless = !!config.footless;
-       this.small = !!config.small;
-       this.onWindowMouseWheelHandler = OO.ui.bind( this.onWindowMouseWheel, this );
-       this.onDocumentKeyDownHandler = OO.ui.bind( this.onDocumentKeyDown, this );
-
-       // Events
-       this.$element.on( 'mousedown', false );
-
-       // Initialization
-       this.$element.addClass( 'oo-ui-dialog' );
-};
-
-/* Inheritance */
-
-OO.inheritClass( OO.ui.Dialog, OO.ui.Window );
-
-/* Static Properties */
-
-/**
- * Symbolic name of dialog.
- *
- * @abstract
- * @static
- * @property {string}
- * @inheritable
- */
-OO.ui.Dialog.static.name = '';
-
-/* Methods */
-
-/**
- * Handle close button click events.
- *
- * @method
- */
-OO.ui.Dialog.prototype.onCloseButtonClick = function () {
-       this.close( { 'action': 'cancel' } );
-};
-
-/**
- * Handle window mouse wheel events.
- *
- * @method
- * @param {jQuery.Event} e Mouse wheel event
- */
-OO.ui.Dialog.prototype.onWindowMouseWheel = function () {
-       return false;
-};
-
-/**
- * Handle document key down events.
- *
- * @method
- * @param {jQuery.Event} e Key down event
- */
-OO.ui.Dialog.prototype.onDocumentKeyDown = function ( e ) {
-       switch ( e.which ) {
-               case OO.ui.Keys.PAGEUP:
-               case OO.ui.Keys.PAGEDOWN:
-               case OO.ui.Keys.END:
-               case OO.ui.Keys.HOME:
-               case OO.ui.Keys.LEFT:
-               case OO.ui.Keys.UP:
-               case OO.ui.Keys.RIGHT:
-               case OO.ui.Keys.DOWN:
-                       // Prevent any key events that might cause scrolling
-                       return false;
-       }
-};
-
-/**
- * Handle frame document key down events.
- *
- * @method
- * @param {jQuery.Event} e Key down event
- */
-OO.ui.Dialog.prototype.onFrameDocumentKeyDown = function ( e ) {
-       if ( e.which === OO.ui.Keys.ESCAPE ) {
-               this.close( { 'action': 'cancel' } );
-               return false;
-       }
-};
-
-/**
- * @inheritdoc
- */
-OO.ui.Dialog.prototype.initialize = function () {
-       // Parent method
-       OO.ui.Window.prototype.initialize.call( this );
-
-       // Properties
-       this.closeButton = new OO.ui.ButtonWidget( {
-               '$': this.$,
-               'frameless': true,
-               'icon': 'close',
-               'title': OO.ui.msg( 'ooui-dialog-action-close' )
-       } );
-
-       // Events
-       this.closeButton.connect( this, { 'click': 'onCloseButtonClick' } );
-       this.frame.$document.on( 'keydown', OO.ui.bind( this.onFrameDocumentKeyDown, this ) );
-
-       // Initialization
-       this.frame.$content.addClass( 'oo-ui-dialog-content' );
-       if ( this.footless ) {
-               this.frame.$content.addClass( 'oo-ui-dialog-content-footless' );
-       }
-       if ( this.small ) {
-               this.$frame.addClass( 'oo-ui-window-frame-small' );
-       }
-       this.closeButton.$element.addClass( 'oo-ui-window-closeButton' );
-       this.$head.append( this.closeButton.$element );
-};
-
-/**
- * @inheritdoc
- */
-OO.ui.Dialog.prototype.setup = function ( data ) {
-       // Parent method
-       OO.ui.Window.prototype.setup.call( this, data );
-
-       // Prevent scrolling in top-level window
-       this.$( window ).on( 'mousewheel', this.onWindowMouseWheelHandler );
-       this.$( document ).on( 'keydown', this.onDocumentKeyDownHandler );
-};
-
-/**
- * @inheritdoc
- */
-OO.ui.Dialog.prototype.teardown = function ( data ) {
-       // Parent method
-       OO.ui.Window.prototype.teardown.call( this, data );
-
-       // Allow scrolling in top-level window
-       this.$( window ).off( 'mousewheel', this.onWindowMouseWheelHandler );
-       this.$( document ).off( 'keydown', this.onDocumentKeyDownHandler );
-};
-
-/**
- * @inheritdoc
- */
-OO.ui.Dialog.prototype.close = function ( data ) {
-       if ( !this.opening && !this.closing && this.visible ) {
-               // Trigger transition
-               this.$element.addClass( 'oo-ui-dialog-closing' );
-               // Allow transition to complete before actually closing
-               setTimeout( OO.ui.bind( function () {
-                       this.$element.removeClass( 'oo-ui-dialog-closing' );
-                       // Parent method
-                       OO.ui.Window.prototype.close.call( this, data );
-               }, this ), 250 );
-       }
-};
-/**
- * Container for elements.
- *
- * @class
- * @abstract
- * @extends OO.ui.Element
- * @mixin OO.EventEmitter
- *
- * @constructor
- * @param {Object} [config] Configuration options
- */
-OO.ui.Layout = function OoUiLayout( config ) {
-       // Initialize config
-       config = config || {};
-
-       // Parent constructor
-       OO.ui.Element.call( this, config );
-
-       // Mixin constructors
-       OO.EventEmitter.call( this );
-
-       // Initialization
-       this.$element.addClass( 'oo-ui-layout' );
-};
-
-/* Inheritance */
-
-OO.inheritClass( OO.ui.Layout, OO.ui.Element );
-
-OO.mixinClass( OO.ui.Layout, OO.EventEmitter );
-/**
- * User interface control.
- *
- * @class
- * @abstract
- * @extends OO.ui.Element
- * @mixin OO.EventEmitter
- *
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {boolean} [disabled=false] Disable
- */
-OO.ui.Widget = function OoUiWidget( config ) {
-       // Initialize config
-       config = $.extend( { 'disabled': false }, config );
-
-       // Parent constructor
-       OO.ui.Element.call( this, config );
-
-       // Mixin constructors
-       OO.EventEmitter.call( this );
-
-       // Properties
-       this.disabled = config.disabled;
-
-       // Initialization
-       this.$element.addClass( 'oo-ui-widget' );
-       this.setDisabled( this.disabled );
-};
-
-/* Inheritance */
-
-OO.inheritClass( OO.ui.Widget, OO.ui.Element );
-
-OO.mixinClass( OO.ui.Widget, OO.EventEmitter );
-
-/* Methods */
-
-/**
- * Check if the widget is disabled.
- *
- * @method
- * @param {boolean} Button is disabled
- */
-OO.ui.Widget.prototype.isDisabled = function () {
-       return this.disabled;
-};
-
-/**
- * Set the disabled state of the widget.
- *
- * This should probably change the widgets's appearance and prevent it from being used.
- *
- * @method
- * @param {boolean} disabled Disable button
- * @chainable
- */
-OO.ui.Widget.prototype.setDisabled = function ( disabled ) {
-       this.disabled = !!disabled;
-       if ( this.disabled ) {
-               this.$element.addClass( 'oo-ui-widget-disabled' );
-       } else {
-               this.$element.removeClass( 'oo-ui-widget-disabled' );
-       }
-       return this;
-};
-/**
- * Element with a button.
- *
- * @class
- * @abstract
- *
- * @constructor
- * @param {jQuery} $button Button node, assigned to #$button
- * @param {Object} [config] Configuration options
- * @cfg {boolean} [frameless] Render button without a frame
- * @cfg {number} [tabIndex] Button's tab index
- */
-OO.ui.ButtonedElement = function OoUiButtonedElement( $button, config ) {
-       // Configuration initialization
-       config = config || {};
-
-       // Properties
-       this.$button = $button;
-       this.tabIndex = null;
-       this.active = false;
-       this.onMouseUpHandler = OO.ui.bind( this.onMouseUp, this );
-
-       // Events
-       this.$button.on( 'mousedown', OO.ui.bind( this.onMouseDown, this ) );
-
-       // Initialization
-       this.$element.addClass( 'oo-ui-buttonedElement' );
-       this.$button
-               .addClass( 'oo-ui-buttonedElement-button' )
-               .attr( 'role', 'button' )
-               .prop( 'tabIndex', config.tabIndex || 0 );
-       if ( config.frameless ) {
-               this.$element.addClass( 'oo-ui-buttonedElement-frameless' );
-       } else {
-               this.$element.addClass( 'oo-ui-buttonedElement-framed' );
-       }
-};
-
-/* Methods */
-
-/**
- * Handles mouse down events.
- *
- * @method
- * @param {jQuery.Event} e Mouse down event
- */
-OO.ui.ButtonedElement.prototype.onMouseDown = function () {
-       this.tabIndex = this.$button.attr( 'tabIndex' );
-       // Remove the tab-index while the button is down to prevent the button from stealing focus
-       this.$button.removeAttr( 'tabIndex' );
-       this.getElementDocument().addEventListener( 'mouseup', this.onMouseUpHandler, true );
-};
-
-/**
- * Handles mouse up events.
- *
- * @method
- * @param {jQuery.Event} e Mouse up event
- */
-OO.ui.ButtonedElement.prototype.onMouseUp = function () {
-       // Restore the tab-index after the button is up to restore the button's accesssibility
-       this.$button.attr( 'tabIndex', this.tabIndex );
-       this.getElementDocument().removeEventListener( 'mouseup', this.onMouseUpHandler, true );
-};
-
-/**
- * Set active state.
- *
- * @method
- * @param {boolean} [value] Make button active
- * @chainable
- */
-OO.ui.ButtonedElement.prototype.setActive = function ( value ) {
-       this.$element.toggleClass( 'oo-ui-buttonedElement-active', !!value );
-       return this;
-};
-/**
- * Element that can be automatically clipped to visible boundaies.
- *
- * @class
- * @abstract
- *
- * @constructor
- * @param {jQuery} $clippable Nodes to clip, assigned to #$clippable
- */
-OO.ui.ClippableElement = function OoUiClippableElement( $clippable ) {
-       // Properties
-       this.$clippable = $clippable;
-       this.clipping = false;
-       this.clipped = false;
-       this.$clippableContainer = null;
-       this.$clippableScroller = null;
-       this.$clippableWindow = null;
-       this.idealWidth = null;
-       this.idealHeight = null;
-       this.onClippableContainerScrollHandler = OO.ui.bind( this.clip, this );
-       this.onClippableWindowResizeHandler = OO.ui.bind( this.clip, this );
-
-       // Initialization
-       this.$clippable.addClass( 'oo-ui-clippableElement-clippable' );
-};
-
-/* Methods */
-
-/**
- * Set clipping.
- *
- * @method
- * @param {boolean} value Enable clipping
- * @chainable
- */
-OO.ui.ClippableElement.prototype.setClipping = function ( value ) {
-       value = !!value;
-
-       if ( this.clipping !== value ) {
-               this.clipping = value;
-               if ( this.clipping ) {
-                       this.$clippableContainer = this.$( this.getClosestScrollableElementContainer() );
-                       // If the clippable container is the body, we have to listen to scroll events and check
-                       // jQuery.scrollTop on the window because of browser inconsistencies
-                       this.$clippableScroller = this.$clippableContainer.is( 'body' ) ?
-                               this.$( OO.ui.Element.getWindow( this.$clippableContainer ) ) :
-                               this.$clippableContainer;
-                       this.$clippableScroller.on( 'scroll', this.onClippableContainerScrollHandler );
-                       this.$clippableWindow = this.$( this.getElementWindow() )
-                               .on( 'resize', this.onClippableWindowResizeHandler );
-                       // Initial clip after visible
-                       setTimeout( OO.ui.bind( this.clip, this ) );
-               } else {
-                       this.$clippableContainer = null;
-                       this.$clippableScroller.off( 'scroll', this.onClippableContainerScrollHandler );
-                       this.$clippableScroller = null;
-                       this.$clippableWindow.off( 'resize', this.onClippableWindowResizeHandler );
-                       this.$clippableWindow = null;
-               }
-       }
-
-       return this;
-};
-
-/**
- * Check if the element will be clipped to fit the visible area of the nearest scrollable container.
- *
- * @method
- * @return {boolean} Element will be clipped to the visible area
- */
-OO.ui.ClippableElement.prototype.isClipping = function () {
-       return this.clipping;
-};
-
-/**
- * Check if the bottom or right of the element is being clipped by the nearest scrollable container.
- *
- * @method
- * @return {boolean} Part of the element is being clipped
- */
-OO.ui.ClippableElement.prototype.isClipped = function () {
-       return this.clipped;
-};
-
-/**
- * Set the ideal size.
- *
- * @method
- * @param {number|string} [width] Width as a number of pixels or CSS string with unit suffix
- * @param {number|string} [height] Height as a number of pixels or CSS string with unit suffix
- */
-OO.ui.ClippableElement.prototype.setIdealSize = function ( width, height ) {
-       this.idealWidth = width;
-       this.idealHeight = height;
-};
-
-/**
- * Clip element to visible boundaries and allow scrolling when needed.
- *
- * Element will be clipped the bottom or right of the element is within 10px of the edge of, or
- * overlapped by, the visible area of the nearest scrollable container.
- *
- * @method
- * @chainable
- */
-OO.ui.ClippableElement.prototype.clip = function () {
-       if ( !this.clipping ) {
-               // this.$clippableContainer and this.$clippableWindow are null, so the below will fail
-               return this;
-       }
-
-       var buffer = 10,
-               cOffset = this.$clippable.offset(),
-               ccOffset = this.$clippableContainer.offset() || { 'top': 0, 'left': 0 },
-               ccHeight = this.$clippableContainer.innerHeight() - buffer,
-               ccWidth = this.$clippableContainer.innerWidth() - buffer,
-               scrollTop = this.$clippableScroller.scrollTop(),
-               scrollLeft = this.$clippableScroller.scrollLeft(),
-               desiredWidth = ( ccOffset.left + scrollLeft + ccWidth ) - cOffset.left,
-               desiredHeight = ( ccOffset.top + scrollTop + ccHeight ) - cOffset.top,
-               naturalWidth = this.$clippable.prop( 'scrollWidth' ),
-               naturalHeight = this.$clippable.prop( 'scrollHeight' ),
-               clipWidth = desiredWidth < naturalWidth,
-               clipHeight = desiredHeight < naturalHeight;
-
-       if ( clipWidth ) {
-               this.$clippable.css( { 'overflow-x': 'auto', 'width': desiredWidth } );
-       } else {
-               this.$clippable.css( { 'overflow-x': '', 'width': this.idealWidth || '' } );
-       }
-       if ( clipHeight ) {
-               this.$clippable.css( { 'overflow-y': 'auto', 'height': desiredHeight } );
-       } else {
-               this.$clippable.css( { 'overflow-y': '', 'height': this.idealHeight || '' } );
-       }
-
-       this.clipped = clipWidth || clipHeight;
-
-       return this;
-};
-/**
- * Element with named flags, used for styling, that can be added, removed and listed and checked.
- *
- * @class
- * @abstract
- *
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {string[]} [flags=[]] Styling flags, e.g. 'primary', 'destructive' or 'constructive'
- */
-OO.ui.FlaggableElement = function OoUiFlaggableElement( config ) {
-       // Config initialization
-       config = config || {};
-
-       // Properties
-       this.flags = {};
-
-       // Initialization
-       this.setFlags( config.flags );
-};
-
-/* Methods */
-
-/**
- * Check if a flag is set.
- *
- * @method
- * @param {string} flag Flag name to check
- * @returns {boolean} Has flag
- */
-OO.ui.FlaggableElement.prototype.hasFlag = function ( flag ) {
-       return flag in this.flags;
-};
-
-/**
- * Get the names of all flags.
- *
- * @method
- * @returns {string[]} flags Flag names
- */
-OO.ui.FlaggableElement.prototype.getFlags = function () {
-       return Object.keys( this.flags );
-};
-
-/**
- * Add one or more flags.
- *
- * @method
- * @param {string[]|Object.<string, boolean>} flags List of flags to add, or list of set/remove
- *  values, keyed by flag name
- * @chainable
- */
-OO.ui.FlaggableElement.prototype.setFlags = function ( flags ) {
-       var i, len, flag,
-               classPrefix = 'oo-ui-flaggableElement-';
-
-       if ( Array.isArray( flags ) ) {
-               for ( i = 0, len = flags.length; i < len; i++ ) {
-                       flag = flags[i];
-                       // Set
-                       this.flags[flag] = true;
-                       this.$element.addClass( classPrefix + flag );
-               }
-       } else if ( OO.isPlainObject( flags ) ) {
-               for ( flag in flags ) {
-                       if ( flags[flags] ) {
-                               // Set
-                               this.flags[flag] = true;
-                               this.$element.addClass( classPrefix + flag );
-                       } else {
-                               // Remove
-                               delete this.flags[flag];
-                               this.$element.removeClass( classPrefix + flag );
-                       }
-               }
-       }
-       return this;
-};
-/**
- * Element containing a sequence of child elements.
- *
- * @class
- * @abstract
- *
- * @constructor
- * @param {jQuery} $group Container node, assigned to #$group
- * @param {Object} [config] Configuration options
- * @cfg {Object.<string,string>} [aggregations] Events to aggregate, keyed by item event name
- */
-OO.ui.GroupElement = function OoUiGroupElement( $group, config ) {
-       // Configuration
-       config = config || {};
-
-       // Properties
-       this.$group = $group;
-       this.items = [];
-       this.$items = this.$( [] );
-       this.aggregate = !$.isEmptyObject( config.aggregations );
-       this.aggregations = config.aggregations || {};
-};
-
-/* Methods */
-
-/**
- * Get items.
- *
- * @method
- * @returns {OO.ui.Element[]} Items
- */
-OO.ui.GroupElement.prototype.getItems = function () {
-       return this.items.slice( 0 );
-};
-
-/**
- * Add items.
- *
- * @method
- * @param {OO.ui.Element[]} items Item
- * @param {number} [index] Index to insert items at
- * @chainable
- */
-OO.ui.GroupElement.prototype.addItems = function ( items, index ) {
-       var i, len, item, event, events, currentIndex,
-               $items = this.$( [] );
-
-       for ( i = 0, len = items.length; i < len; i++ ) {
-               item = items[i];
-
-               // Check if item exists then remove it first, effectively "moving" it
-               currentIndex = this.items.indexOf( item );
-               if ( currentIndex >= 0 ) {
-                       this.removeItems( [ item ] );
-                       // Adjust index to compensate for removal
-                       if ( currentIndex < index ) {
-                               index--;
-                       }
-               }
-               // Add the item
-               if ( this.aggregate ) {
-                       events = {};
-                       for ( event in this.aggregations ) {
-                               events[event] = [ 'emit', this.aggregations[event], item ];
-                       }
-                       item.connect( this, events );
-               }
-               $items = $items.add( item.$element );
-       }
-
-       if ( index === undefined || index < 0 || index >= this.items.length ) {
-               this.$group.append( $items );
-               this.items.push.apply( this.items, items );
-       } else if ( index === 0 ) {
-               this.$group.prepend( $items );
-               this.items.unshift.apply( this.items, items );
-       } else {
-               this.$items.eq( index ).before( $items );
-               this.items.splice.apply( this.items, [ index, 0 ].concat( items ) );
-       }
-
-       this.$items = this.$items.add( $items );
-
-       return this;
-};
-
-/**
- * Remove items.
- *
- * Items will be detached, not removed, so they can be used later.
- *
- * @method
- * @param {OO.ui.Element[]} items Items to remove
- * @chainable
- */
-OO.ui.GroupElement.prototype.removeItems = function ( items ) {
-       var i, len, item, index;
-
-       // Remove specific items
-       for ( i = 0, len = items.length; i < len; i++ ) {
-               item = items[i];
-               index = this.items.indexOf( item );
-               if ( index !== -1 ) {
-                       if ( this.aggregate ) {
-                               item.disconnect( this );
-                       }
-                       this.items.splice( index, 1 );
-                       item.$element.detach();
-                       this.$items = this.$items.not( item.$element );
-               }
-       }
-
-       return this;
-};
-
-/**
- * Clear all items.
- *
- * Items will be detached, not removed, so they can be used later.
- *
- * @method
- * @chainable
- */
-OO.ui.GroupElement.prototype.clearItems = function () {
-       var i, len, item;
-
-       // Remove all items
-       if ( this.aggregate ) {
-               for ( i = 0, len = this.items.length; i < len; i++ ) {
-                       item.disconnect( this );
-               }
-       }
-       this.items = [];
-       this.$items.detach();
-       this.$items = this.$( [] );
-};
-/**
- * Element containing an icon.
- *
- * @class
- * @abstract
- *
- * @constructor
- * @param {jQuery} $icon Icon node, assigned to #$icon
- * @param {Object} [config] Configuration options
- * @cfg {Object|string} [icon=''] Symbolic icon name, or map of icon names keyed by language ID;
- *  use the 'default' key to specify the icon to be used when there is no icon in the user's
- *  language
- */
-OO.ui.IconedElement = function OoUiIconedElement( $icon, config ) {
-       // Config intialization
-       config = config || {};
-
-       // Properties
-       this.$icon = $icon;
-       this.icon = null;
-
-       // Initialization
-       this.$icon.addClass( 'oo-ui-iconedElement-icon' );
-       this.setIcon( config.icon || this.constructor.static.icon );
-};
-
-/* Static Properties */
-
-OO.ui.IconedElement.static = {};
-
-/**
- * Icon.
- *
- * Value should be the unique portion of an icon CSS class name, such as 'up' for 'oo-ui-icon-up'.
- *
- * For i18n purposes, this property can be an object containing a `default` icon name property and
- * additional icon names keyed by language code.
- *
- * Example of i18n icon definition:
- *     { 'default': 'bold-a', 'en': 'bold-b', 'de': 'bold-f' }
- *
- * @static
- * @inheritable
- * @property {Object|string} Symbolic icon name, or map of icon names keyed by language ID;
- *  use the 'default' key to specify the icon to be used when there is no icon in the user's
- *  language
- */
-OO.ui.IconedElement.static.icon = null;
-
-/* Methods */
-
-/**
- * Set icon.
- *
- * @method
- * @param {Object|string} icon Symbolic icon name, or map of icon names keyed by language ID;
- *  use the 'default' key to specify the icon to be used when there is no icon in the user's
- *  language
- * @chainable
- */
-OO.ui.IconedElement.prototype.setIcon = function ( icon ) {
-       icon = OO.isPlainObject( icon ) ? OO.ui.getLocalValue( icon, null, 'default' ) : icon;
-
-       if ( this.icon ) {
-               this.$icon.removeClass( 'oo-ui-icon-' + this.icon );
-       }
-       if ( typeof icon === 'string' ) {
-               icon = icon.trim();
-               if ( icon.length ) {
-                       this.$icon.addClass( 'oo-ui-icon-' + icon );
-                       this.icon = icon;
-               }
-       }
-       this.$element.toggleClass( 'oo-ui-iconedElement', !!this.icon );
-
-       return this;
-};
-
-/**
- * Get icon.
- *
- * @method
- * @returns {string} Icon
- */
-OO.ui.IconedElement.prototype.getIcon = function () {
-       return this.icon;
-};
-/**
- * Element containing an indicator.
- *
- * @class
- * @abstract
- *
- * @constructor
- * @param {jQuery} $indicator Indicator node, assigned to #$indicator
- * @param {Object} [config] Configuration options
- * @cfg {string} [indicator] Symbolic indicator name
- * @cfg {string} [indicatorTitle] Indicator title text or a function that return text
- */
-OO.ui.IndicatedElement = function OoUiIndicatedElement( $indicator, config ) {
-       // Config intialization
-       config = config || {};
-
-       // Properties
-       this.$indicator = $indicator;
-       this.indicator = null;
-       this.indicatorLabel = null;
-
-       // Initialization
-       this.$indicator.addClass( 'oo-ui-indicatedElement-indicator' );
-       this.setIndicator( config.indicator || this.constructor.static.indicator );
-       this.setIndicatorTitle( config.indicatorTitle  || this.constructor.static.indicatorTitle );
-};
-
-/* Static Properties */
-
-OO.ui.IndicatedElement.static = {};
-
-/**
- * indicator.
- *
- * @static
- * @inheritable
- * @property {string|null} Symbolic indicator name or null for no indicator
- */
-OO.ui.IndicatedElement.static.indicator = null;
-
-/**
- * Indicator title.
- *
- * @static
- * @inheritable
- * @property {string|Function|null} Indicator title text, a function that return text or null for no
- *  indicator title
- */
-OO.ui.IndicatedElement.static.indicatorTitle = null;
-
-/* Methods */
-
-/**
- * Set indicator.
- *
- * @method
- * @param {string|null} indicator Symbolic name of indicator to use or null for no indicator
- * @chainable
- */
-OO.ui.IndicatedElement.prototype.setIndicator = function ( indicator ) {
-       if ( this.indicator ) {
-               this.$indicator.removeClass( 'oo-ui-indicator-' + this.indicator );
-               this.indicator = null;
-       }
-       if ( typeof indicator === 'string' ) {
-               indicator = indicator.trim();
-               if ( indicator.length ) {
-                       this.$indicator.addClass( 'oo-ui-indicator-' + indicator );
-                       this.indicator = indicator;
-               }
-       }
-       this.$element.toggleClass( 'oo-ui-indicatedElement', !!this.indicator );
-
-       return this;
-};
-
-/**
- * Set indicator label.
- *
- * @method
- * @param {string|Function|null} indicator Indicator title text, a function that return text or null
- *  for no indicator title
- * @chainable
- */
-OO.ui.IndicatedElement.prototype.setIndicatorTitle = function ( indicatorTitle ) {
-       this.indicatorTitle = indicatorTitle = OO.ui.resolveMsg( indicatorTitle );
-
-       if ( typeof indicatorTitle === 'string' && indicatorTitle.length ) {
-               this.$indicator.attr( 'title', indicatorTitle );
-       } else {
-               this.$indicator.removeAttr( 'title' );
-       }
-
-       return this;
-};
-
-/**
- * Get indicator.
- *
- * @method
- * @returns {string} title Symbolic name of indicator
- */
-OO.ui.IndicatedElement.prototype.getIndicator = function () {
-       return this.indicator;
-};
-
-/**
- * Get indicator title.
- *
- * @method
- * @returns {string} Indicator title text
- */
-OO.ui.IndicatedElement.prototype.getIndicatorTitle = function () {
-       return this.indicatorTitle;
-};
-/**
- * Element containing a label.
- *
- * @class
- * @abstract
- *
- * @constructor
- * @param {jQuery} $label Label node, assigned to #$label
- * @param {Object} [config] Configuration options
- * @cfg {jQuery|string|Function} [label] Label nodes, text or a function that returns nodes or text
- */
-OO.ui.LabeledElement = function OoUiLabeledElement( $label, config ) {
-       // Config intialization
-       config = config || {};
-
-       // Properties
-       this.$label = $label;
-       this.label = null;
-
-       // Initialization
-       this.$label.addClass( 'oo-ui-labeledElement-label' );
-       this.setLabel( config.label || this.constructor.static.label );
-};
-
-/* Static Properties */
-
-OO.ui.LabeledElement.static = {};
-
-/**
- * Label.
- *
- * @static
- * @inheritable
- * @property {string|Function|null} Label text; a function that returns a nodes or text; or null for
- *  no label
- */
-OO.ui.LabeledElement.static.label = null;
-
-/* Methods */
-
-/**
- * Set the label.
- *
- * @method
- * @param {jQuery|string|Function|null} label Label nodes; text; a function that retuns nodes or
- *  text; or null for no label
- * @chainable
- */
-OO.ui.LabeledElement.prototype.setLabel = function ( label ) {
-       var empty = false;
-
-       this.label = label = OO.ui.resolveMsg( label ) || null;
-       if ( typeof label === 'string' && label.trim() ) {
-               this.$label.text( label );
-       } else if ( label instanceof jQuery ) {
-               this.$label.empty().append( label );
-       } else {
-               this.$label.empty();
-               empty = true;
-       }
-       this.$element.toggleClass( 'oo-ui-labeledElement', !empty );
-       this.$label.css( 'display', empty ? 'none' : '' );
-
-       return this;
-};
-
-/**
- * Get the label.
- *
- * @method
- * @returns {jQuery|string|Function|null} label Label nodes; text; a function that returns nodes or
- *  text; or null for no label
- */
-OO.ui.LabeledElement.prototype.getLabel = function () {
-       return this.label;
-};
-
-/**
- * Fit the label.
- *
- * @method
- * @chainable
- */
-OO.ui.LabeledElement.prototype.fitLabel = function () {
-       if ( this.$label.autoEllipsis ) {
-               this.$label.autoEllipsis( { 'hasSpan': false, 'tooltip': true } );
-       }
-       return this;
-};
-/**
- * Popuppable element.
- *
- * @class
- * @abstract
- *
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {number} [popupWidth=320] Width of popup
- * @cfg {number} [popupHeight] Height of popup
- * @cfg {Object} [popup] Configuration to pass to popup
- */
-OO.ui.PopuppableElement = function OoUiPopuppableElement( config ) {
-       // Configuration initialization
-       config = $.extend( { 'popupWidth': 320 }, config );
-
-       // Properties
-       this.popup = new OO.ui.PopupWidget( $.extend(
-               { 'align': 'center', 'autoClose': true },
-               config.popup,
-               { '$': this.$, '$autoCloseIgnore': this.$element }
-       ) );
-       this.popupWidth = config.popupWidth;
-       this.popupHeight = config.popupHeight;
-};
-
-/* Methods */
-
-/**
- * Get popup.
- *
- * @method
- * @returns {OO.ui.PopupWidget} Popup widget
- */
-OO.ui.PopuppableElement.prototype.getPopup = function () {
-       return this.popup;
-};
-
-/**
- * Show popup.
- *
- * @method
- */
-OO.ui.PopuppableElement.prototype.showPopup = function () {
-       this.popup.show().display( this.popupWidth, this.popupHeight );
-};
-
-/**
- * Hide popup.
- *
- * @method
- */
-OO.ui.PopuppableElement.prototype.hidePopup = function () {
-       this.popup.hide();
-};
-/**
- * Element with a title.
- *
- * @class
- * @abstract
- *
- * @constructor
- * @param {jQuery} $label Titled node, assigned to #$titled
- * @param {Object} [config] Configuration options
- * @cfg {string|Function} [title] Title text or a function that returns text
- */
-OO.ui.TitledElement = function OoUiTitledElement( $titled, config ) {
-       // Config intialization
-       config = config || {};
-
-       // Properties
-       this.$titled = $titled;
-       this.title = null;
-
-       // Initialization
-       this.setTitle( config.title || this.constructor.static.title );
-};
-
-/* Static Properties */
-
-OO.ui.TitledElement.static = {};
-
-/**
- * Title.
- *
- * @static
- * @inheritable
- * @property {string|Function} Title text or a function that returns text
- */
-OO.ui.TitledElement.static.title = null;
-
-/* Methods */
-
-/**
- * Set title.
- *
- * @method
- * @param {string|Function|null} title Title text, a function that returns text or null for no title
- * @chainable
- */
-OO.ui.TitledElement.prototype.setTitle = function ( title ) {
-       this.title = title = OO.ui.resolveMsg( title ) || null;
-
-       if ( typeof title === 'string' && title.length ) {
-               this.$titled.attr( 'title', title );
-       } else {
-               this.$titled.removeAttr( 'title' );
-       }
-
-       return this;
-};
-
-/**
- * Get title.
- *
- * @method
- * @returns {string} Title string
- */
-OO.ui.TitledElement.prototype.getTitle = function () {
-       return this.title;
-};
-/**
- * Generic toolbar tool.
- *
- * @class
- * @abstract
- * @extends OO.ui.Widget
- * @mixins OO.ui.IconedElement
- *
- * @constructor
- * @param {OO.ui.ToolGroup} toolGroup
- * @param {Object} [config] Configuration options
- * @cfg {string|Function} [title] Title text or a function that returns text
- */
-OO.ui.Tool = function OoUiTool( toolGroup, config ) {
-       // Config intialization
-       config = config || {};
-
-       // Parent constructor
-       OO.ui.Widget.call( this, config );
-
-       // Mixin constructors
-       OO.ui.IconedElement.call( this, this.$( '<span>' ), config );
-
-       // Properties
-       this.toolGroup = toolGroup;
-       this.toolbar = this.toolGroup.getToolbar();
-       this.active = false;
-       this.$title = this.$( '<span>' );
-       this.$link = this.$( '<a>' );
-       this.title = null;
-
-       // Events
-       this.toolbar.connect( this, { 'updateState': 'onUpdateState' } );
-
-       // Initialization
-       this.$title.addClass( 'oo-ui-tool-title' );
-       this.$link
-               .addClass( 'oo-ui-tool-link' )
-               .append( this.$icon, this.$title );
-       this.$element
-               .data( 'oo-ui-tool', this )
-               .addClass(
-                       'oo-ui-tool ' + 'oo-ui-tool-name-' +
-                       this.constructor.static.name.replace( /^([^\/]+)\/([^\/]+).*$/, '$1-$2' )
-               )
-               .append( this.$link );
-       this.setTitle( config.title || this.constructor.static.title );
-};
-
-/* Inheritance */
-
-OO.inheritClass( OO.ui.Tool, OO.ui.Widget );
-
-OO.mixinClass( OO.ui.Tool, OO.ui.IconedElement );
-
-/* Events */
-
-/**
- * @event select
- */
-
-/* Static Properties */
-
-OO.ui.Tool.static.tagName = 'span';
-
-/**
- * Symbolic name of tool.
- *
- * @abstract
- * @static
- * @property {string}
- * @inheritable
- */
-OO.ui.Tool.static.name = '';
-
-/**
- * Tool group.
- *
- * @abstract
- * @static
- * @property {string}
- * @inheritable
- */
-OO.ui.Tool.static.group = '';
-
-/**
- * Tool title.
- *
- * Title is used as a tooltip when the tool is part of a bar tool group, or a label when the tool
- * is part of a list or menu tool group. If a trigger is associated with an action by the same name
- * as the tool, a description of its keyboard shortcut for the appropriate platform will be
- * appended to the title if the tool is part of a bar tool group.
- *
- * @abstract
- * @static
- * @property {string|Function} Title text or a function that returns text
- * @inheritable
- */
-OO.ui.Tool.static.title = '';
-
-/**
- * Tool can be automatically added to tool groups.
- *
- * @static
- * @property {boolean}
- * @inheritable
- */
-OO.ui.Tool.static.autoAdd = true;
-
-/**
- * Check if this tool is compatible with given data.
- *
- * @method
- * @static
- * @inheritable
- * @param {Mixed} data Data to check
- * @returns {boolean} Tool can be used with data
- */
-OO.ui.Tool.static.isCompatibleWith = function () {
-       return false;
-};
-
-/* Methods */
-
-/**
- * Handle the toolbar state being updated.
- *
- * This is an abstract method that must be overridden in a concrete subclass.
- *
- * @abstract
- * @method
- */
-OO.ui.Tool.prototype.onUpdateState = function () {
-       throw new Error(
-               'OO.ui.Tool.onUpdateState not implemented in this subclass:' + this.constructor
-       );
-};
-
-/**
- * Handle the tool being selected.
- *
- * This is an abstract method that must be overridden in a concrete subclass.
- *
- * @abstract
- * @method
- */
-OO.ui.Tool.prototype.onSelect = function () {
-       throw new Error(
-               'OO.ui.Tool.onSelect not implemented in this subclass:' + this.constructor
-       );
-};
-
-/**
- * Check if the button is active.
- *
- * @method
- * @param {boolean} Button is active
- */
-OO.ui.Tool.prototype.isActive = function () {
-       return this.active;
-};
-
-/**
- * Make the button appear active or inactive.
- *
- * @method
- * @param {boolean} state Make button appear active
- */
-OO.ui.Tool.prototype.setActive = function ( state ) {
-       this.active = !!state;
-       if ( this.active ) {
-               this.$element.addClass( 'oo-ui-tool-active' );
-       } else {
-               this.$element.removeClass( 'oo-ui-tool-active' );
-       }
-};
-
-/**
- * Get the tool title.
- *
- * @method
- * @param {string|Function} title Title text or a function that returns text
- * @chainable
- */
-OO.ui.Tool.prototype.setTitle = function ( title ) {
-       this.title = OO.ui.resolveMsg( title );
-       this.updateTitle();
-       return this;
-};
-
-/**
- * Get the tool title.
- *
- * @method
- * @returns {string} Title text
- */
-OO.ui.Tool.prototype.getTitle = function () {
-       return this.title;
-};
-
-/**
- * Get the tool's symbolic name.
- *
- * @method
- * @returns {string} Symbolic name of tool
- */
-OO.ui.Tool.prototype.getName = function () {
-       return this.constructor.static.name;
-};
-
-/**
- * Update the title.
- *
- * @method
- */
-OO.ui.Tool.prototype.updateTitle = function () {
-       var titleTooltips = this.toolGroup.constructor.static.titleTooltips,
-               accelTooltips = this.toolGroup.constructor.static.accelTooltips,
-               accel = this.toolbar.getToolAccelerator( this.constructor.static.name ),
-               tooltipParts = [];
-
-       this.$title.empty()
-               .text( this.title )
-               .append(
-                       this.$( '<span>' )
-                               .addClass( 'oo-ui-tool-accel' )
-                               .text( accel )
-               );
-
-       if ( titleTooltips && typeof this.title === 'string' && this.title.length ) {
-               tooltipParts.push( this.title );
-       }
-       if ( accelTooltips && typeof accel === 'string' && accel.length ) {
-               tooltipParts.push( accel );
-       }
-       if ( tooltipParts.length ) {
-               this.$link.attr( 'title', tooltipParts.join( ' ' ) );
-       } else {
-               this.$link.removeAttr( 'title' );
-       }
-};
-
-/**
- * Destroy tool.
- *
- * @method
- */
-OO.ui.Tool.prototype.destroy = function () {
-       this.toolbar.disconnect( this );
-       this.$element.remove();
-};
-/**
- * Collection of tool groups.
- *
- * @class
- * @extends OO.ui.Element
- * @mixins OO.EventEmitter
- * @mixins OO.ui.GroupElement
- *
- * @constructor
- * @param {OO.Factory} toolFactory Factory for creating tools
- * @param {Object} [options] Configuration options
- * @cfg {boolean} [actions] Add an actions section opposite to the tools
- * @cfg {boolean} [shadow] Add a shadow below the toolbar
- */
-OO.ui.Toolbar = function OoUiToolbar( toolFactory, options ) {
-       // Configuration initialization
-       options = options || {};
-
-       // Parent constructor
-       OO.ui.Element.call( this, options );
-
-       // Mixin constructors
-       OO.EventEmitter.call( this );
-       OO.ui.GroupElement.call( this, this.$( '<div>' ) );
-
-       // Properties
-       this.toolFactory = toolFactory;
-       this.groups = [];
-       this.tools = {};
-       this.$bar = this.$( '<div>' );
-       this.$actions = this.$( '<div>' );
-       this.initialized = false;
-
-       // Events
-       this.$element
-               .add( this.$bar ).add( this.$group ).add( this.$actions )
-               .on( 'mousedown', OO.ui.bind( this.onMouseDown, this ) );
-
-       // Initialization
-       this.$group.addClass( 'oo-ui-toolbar-tools' );
-       this.$bar.addClass( 'oo-ui-toolbar-bar' ).append( this.$group );
-       if ( options.actions ) {
-               this.$actions.addClass( 'oo-ui-toolbar-actions' );
-               this.$bar.append( this.$actions );
-       }
-       this.$bar.append( '<div style="clear:both"></div>' );
-       if ( options.shadow ) {
-               this.$bar.append( '<div class="oo-ui-toolbar-shadow"></div>' );
-       }
-       this.$element.addClass( 'oo-ui-toolbar' ).append( this.$bar );
-};
-
-/* Inheritance */
-
-OO.inheritClass( OO.ui.Toolbar, OO.ui.Element );
-
-OO.mixinClass( OO.ui.Toolbar, OO.EventEmitter );
-OO.mixinClass( OO.ui.Toolbar, OO.ui.GroupElement );
-
-/* Methods */
-
-/**
- * Get the tool factory.
- *
- * @method
- * @returns {OO.Factory} Tool factory
- */
-OO.ui.Toolbar.prototype.getToolFactory = function () {
-       return this.toolFactory;
-};
-
-/**
- * Handles mouse down events.
- *
- * @method
- * @param {jQuery.Event} e Mouse down event
- */
-OO.ui.Toolbar.prototype.onMouseDown = function ( e ) {
-       var $closestWidgetToEvent = this.$( e.target ).closest( '.oo-ui-widget' ),
-               $closestWidgetToToolbar = this.$element.closest( '.oo-ui-widget' );
-       if ( !$closestWidgetToEvent.length || $closestWidgetToEvent[0] === $closestWidgetToToolbar[0] ) {
-               return false;
-       }
-};
-
-/**
- * Sets up handles and preloads required information for the toolbar to work.
- * This must be called immediately after it is attached to a visible document.
- */
-OO.ui.Toolbar.prototype.initialize = function () {
-       this.initialized = true;
-};
-
-/**
- * Setup toolbar.
- *
- * Tools can be specified in the following ways:
- *  - A specific tool: `{ 'name': 'tool-name' }` or `'tool-name'`
- *  - All tools in a group: `{ 'group': 'group-name' }`
- *  - All tools: `'*'` - Using this will make the group a list with a "More" label by default
- *
- * @method
- * @param {Object.<string,Array>} groups List of tool group configurations
- * @param {Array|string} [groups.include] Tools to include
- * @param {Array|string} [groups.exclude] Tools to exclude
- * @param {Array|string} [groups.promote] Tools to promote to the beginning
- * @param {Array|string} [groups.demote] Tools to demote to the end
- */
-OO.ui.Toolbar.prototype.setup = function ( groups ) {
-       var i, len, type, group,
-               items = [],
-               // TODO: Use a registry instead
-               defaultType = 'bar',
-               constructors = {
-                       'bar': OO.ui.BarToolGroup,
-                       'list': OO.ui.ListToolGroup,
-                       'menu': OO.ui.MenuToolGroup
-               };
-
-       // Cleanup previous groups
-       this.reset();
-
-       // Build out new groups
-       for ( i = 0, len = groups.length; i < len; i++ ) {
-               group = groups[i];
-               if ( group.include === '*' ) {
-                       // Apply defaults to catch-all groups
-                       if ( group.type === undefined ) {
-                               group.type = 'list';
-                       }
-                       if ( group.label === undefined ) {
-                               group.label = 'ooui-toolbar-more';
-                       }
-               }
-               type = constructors[group.type] ? group.type : defaultType;
-               items.push(
-                       new constructors[type]( this, $.extend( { '$': this.$ }, group ) )
-               );
-       }
-       this.addItems( items );
-};
-
-/**
- * Remove all tools and groups from the toolbar.
- */
-OO.ui.Toolbar.prototype.reset = function () {
-       var i, len;
-
-       this.groups = [];
-       this.tools = {};
-       for ( i = 0, len = this.items.length; i < len; i++ ) {
-               this.items[i].destroy();
-       }
-       this.clearItems();
-};
-
-/**
- * Destroys toolbar, removing event handlers and DOM elements.
- *
- * Call this whenever you are done using a toolbar.
- */
-OO.ui.Toolbar.prototype.destroy = function () {
-       this.reset();
-       this.$element.remove();
-};
-
-/**
- * Check if tool has not been used yet.
- *
- * @param {string} name Symbolic name of tool
- * @return {boolean} Tool is available
- */
-OO.ui.Toolbar.prototype.isToolAvailable = function ( name ) {
-       return !this.tools[name];
-};
-
-/**
- * Prevent tool from being used again.
- *
- * @param {OO.ui.Tool} tool Tool to reserve
- */
-OO.ui.Toolbar.prototype.reserveTool = function ( tool ) {
-       this.tools[tool.getName()] = tool;
-};
-
-/**
- * Allow tool to be used again.
- *
- * @param {OO.ui.Tool} tool Tool to release
- */
-OO.ui.Toolbar.prototype.releaseTool = function ( tool ) {
-       delete this.tools[tool.getName()];
-};
-
-/**
- * Get accelerator label for tool.
- *
- * This is a stub that should be overridden to provide access to accelerator information.
- *
- * @param {string} name Symbolic name of tool
- * @returns {string|undefined} Tool accelerator label if available
- */
-OO.ui.Toolbar.prototype.getToolAccelerator = function () {
-       return undefined;
-};
-/**
- * Factory for tools.
- *
- * @class
- * @extends OO.Factory
- * @constructor
- */
-OO.ui.ToolFactory = function OoUiToolFactory() {
-       // Parent constructor
-       OO.Factory.call( this );
-};
-
-/* Inheritance */
-
-OO.inheritClass( OO.ui.ToolFactory, OO.Factory );
-
-/* Methods */
-
-OO.ui.ToolFactory.prototype.getTools = function ( include, exclude, promote, demote ) {
-       var i, len, included, promoted, demoted,
-               auto = [],
-               used = {};
-
-       // Collect included and not excluded tools
-       included = OO.simpleArrayDifference( this.extract( include ), this.extract( exclude ) );
-
-       // Promotion
-       promoted = this.extract( promote, used );
-       demoted = this.extract( demote, used );
-
-       // Auto
-       for ( i = 0, len = included.length; i < len; i++ ) {
-               if ( !used[included[i]] ) {
-                       auto.push( included[i] );
-               }
-       }
-
-       return promoted.concat( auto ).concat( demoted );
-};
-
-/**
- * Get a flat list of names from a list of names or groups.
- *
- * Tools can be specified in the following ways:
- *  - A specific tool: `{ 'name': 'tool-name' }` or `'tool-name'`
- *  - All tools in a group: `{ 'group': 'group-name' }`
- *  - All tools: `'*'`
- *
- * @private
- * @param {Array|string} collection List of tools
- * @param {Object} [used] Object with names that should be skipped as properties; extracted
- *   names will be added as properties
- * @return {string[]} List of extracted names
- */
-OO.ui.ToolFactory.prototype.extract = function ( collection, used ) {
-       var i, len, item, name, tool,
-               names = [];
-
-       if ( collection === '*' ) {
-               for ( name in this.registry ) {
-                       tool = this.registry[name];
-                       if (
-                               // Only add tools by group name when auto-add is enabled
-                               tool.static.autoAdd &&
-                               // Exclude already used tools
-                               ( !used || !used[name] )
-                       ) {
-                               names.push( name );
-                               if ( used ) {
-                                       used[name] = true;
-                               }
-                       }
-               }
-       } else if ( Array.isArray( collection ) ) {
-               for ( i = 0, len = collection.length; i < len; i++ ) {
-                       item = collection[i];
-                       // Allow plain strings as shorthand for named tools
-                       if ( typeof item === 'string' ) {
-                               item = { 'name': item };
-                       }
-                       if ( OO.isPlainObject( item ) ) {
-                               if ( item.group ) {
-                                       for ( name in this.registry ) {
-                                               tool = this.registry[name];
-                                               if (
-                                                       // Include tools with matching group
-                                                       tool.static.group === item.group &&
-                                                       // Only add tools by group name when auto-add is enabled
-                                                       tool.static.autoAdd &&
-                                                       // Exclude already used tools
-                                                       ( !used || !used[name] )
-                                               ) {
-                                                       names.push( name );
-                                                       if ( used ) {
-                                                               used[name] = true;
-                                                       }
-                                               }
-                                       }
-                               }
-                               // Include tools with matching name and exclude already used tools
-                               else if ( item.name && ( !used || !used[item.name] ) ) {
-                                       names.push( item.name );
-                                       if ( used ) {
-                                               used[item.name] = true;
-                                       }
-                               }
-                       }
-               }
-       }
-       return names;
-};
-/**
- * Collection of tools.
- *
- * @class
- * @abstract
- * @extends OO.ui.Widget
- * @mixins OO.ui.GroupElement
- *
- * Tools can be specified in the following ways:
- *  - A specific tool: `{ 'name': 'tool-name' }` or `'tool-name'`
- *  - All tools in a group: `{ 'group': 'group-name' }`
- *  - All tools: `'*'`
- *
- * @constructor
- * @param {OO.ui.Toolbar} toolbar
- * @param {Object} [config] Configuration options
- * @cfg {Array|string} [include=[]] List of tools to include
- * @cfg {Array|string} [exclude=[]] List of tools to exclude
- * @cfg {Array|string} [promote=[]] List of tools to promote to the beginning
- * @cfg {Array|string} [demote=[]] List of tools to demote to the end
- */
-OO.ui.ToolGroup = function OoUiToolGroup( toolbar, config ) {
-       // Configuration initialization
-       config = config || {};
-
-       // Parent constructor
-       OO.ui.Widget.call( this, config );
-
-       // Mixin constructors
-       OO.ui.GroupElement.call( this, this.$( '<div>' ) );
-
-       // Properties
-       this.toolbar = toolbar;
-       this.tools = {};
-       this.pressed = null;
-       this.include = config.include || [];
-       this.exclude = config.exclude || [];
-       this.promote = config.promote || [];
-       this.demote = config.demote || [];
-       this.onCapturedMouseUpHandler = OO.ui.bind( this.onCapturedMouseUp, this );
-
-       // Events
-       this.$element.on( {
-               'mousedown': OO.ui.bind( this.onMouseDown, this ),
-               'mouseup': OO.ui.bind( this.onMouseUp, this ),
-               'mouseover': OO.ui.bind( this.onMouseOver, this ),
-               'mouseout': OO.ui.bind( this.onMouseOut, this )
-       } );
-       this.toolbar.getToolFactory().connect( this, { 'register': 'onToolFactoryRegister' } );
-
-       // Initialization
-       this.$group.addClass( 'oo-ui-toolGroup-tools' );
-       this.$element
-               .addClass( 'oo-ui-toolGroup' )
-               .append( this.$group );
-       this.populate();
-};
-
-/* Inheritance */
-
-OO.inheritClass( OO.ui.ToolGroup, OO.ui.Widget );
-
-OO.mixinClass( OO.ui.ToolGroup, OO.ui.GroupElement );
-
-/* Events */
-
-/**
- * @event update
- */
-
-/* Static Properties */
-
-/**
- * Show labels in tooltips.
- *
- * @static
- * @property {boolean}
- * @inheritable
- */
-OO.ui.ToolGroup.static.titleTooltips = false;
-
-/**
- * Show acceleration labels in tooltips.
- *
- * @static
- * @property {boolean}
- * @inheritable
- */
-OO.ui.ToolGroup.static.accelTooltips = false;
-
-/* Methods */
-
-/**
- * Handle mouse down events.
- *
- * @method
- * @param {jQuery.Event} e Mouse down event
- */
-OO.ui.ToolGroup.prototype.onMouseDown = function ( e ) {
-       if ( !this.disabled && e.which === 1 ) {
-               this.pressed = this.getTargetTool( e );
-               if ( this.pressed ) {
-                       this.pressed.setActive( true );
-                       this.getElementDocument().addEventListener(
-                               'mouseup', this.onCapturedMouseUpHandler, true
-                       );
-                       return false;
-               }
-       }
-};
-
-/**
- * Handle captured mouse up events.
- *
- * @method
- * @param {Event} e Mouse up event
- */
-OO.ui.ToolGroup.prototype.onCapturedMouseUp = function ( e ) {
-       this.getElementDocument().removeEventListener( 'mouseup', this.onCapturedMouseUpHandler, true );
-       // onMouseUp may be called a second time, depending on where the mouse is when the button is
-       // released, but since `this.pressed` will no longer be true, the second call will be ignored.
-       this.onMouseUp( e );
-};
-
-/**
- * Handle mouse up events.
- *
- * @method
- * @param {jQuery.Event} e Mouse up event
- */
-OO.ui.ToolGroup.prototype.onMouseUp = function ( e ) {
-       var tool = this.getTargetTool( e );
-
-       if ( !this.disabled && e.which === 1 && this.pressed && this.pressed === tool ) {
-               this.pressed.onSelect();
-       }
-
-       this.pressed = null;
-       return false;
-};
-
-/**
- * Handle mouse over events.
- *
- * @method
- * @param {jQuery.Event} e Mouse over event
- */
-OO.ui.ToolGroup.prototype.onMouseOver = function ( e ) {
-       var tool = this.getTargetTool( e );
-
-       if ( this.pressed && this.pressed === tool ) {
-               this.pressed.setActive( true );
-       }
-};
-
-/**
- * Handle mouse out events.
- *
- * @method
- * @param {jQuery.Event} e Mouse out event
- */
-OO.ui.ToolGroup.prototype.onMouseOut = function ( e ) {
-       var tool = this.getTargetTool( e );
-
-       if ( this.pressed && this.pressed === tool ) {
-               this.pressed.setActive( false );
-       }
-};
-
-/**
- * Get the closest tool to a jQuery.Event.
- *
- * Only tool links are considered, which prevents other elements in the tool such as popups from
- * triggering tool group interactions.
- *
- * @method
- * @private
- * @param {jQuery.Event} e
- * @returns {OO.ui.Tool|null} Tool, `null` if none was found
- */
-OO.ui.ToolGroup.prototype.getTargetTool = function ( e ) {
-       var tool,
-               $item = this.$( e.target ).closest( '.oo-ui-tool-link' );
-
-       if ( $item.length ) {
-               tool = $item.parent().data( 'oo-ui-tool' );
-       }
-
-       return tool && !tool.isDisabled() ? tool : null;
-};
-
-/**
- * Handle tool registry register events.
- *
- * If a tool is registered after the group is created, we must repopulate the list to account for:
- * - a tool being added that may be included
- * - a tool already included being overridden
- *
- * @param {string} name Symbolic name of tool
- */
-OO.ui.ToolGroup.prototype.onToolFactoryRegister = function () {
-       this.populate();
-};
-
-/**
- * Get the toolbar this group is in.
- *
- * @return {OO.ui.Toolbar} Toolbar of group
- */
-OO.ui.ToolGroup.prototype.getToolbar = function () {
-       return this.toolbar;
-};
-
-/**
- * Add and remove tools based on configuration.
- *
- * @method
- */
-OO.ui.ToolGroup.prototype.populate = function () {
-       var i, len, name, tool,
-               toolFactory = this.toolbar.getToolFactory(),
-               names = {},
-               add = [],
-               remove = [],
-               list = this.toolbar.getToolFactory().getTools(
-                       this.include, this.exclude, this.promote, this.demote
-               );
-
-       // Build a list of needed tools
-       for ( i = 0, len = list.length; i < len; i++ ) {
-               name = list[i];
-               if (
-                       // Tool exists
-                       toolFactory.lookup( name ) &&
-                       // Tool is available or is already in this group
-                       ( this.toolbar.isToolAvailable( name ) || this.tools[name] )
-               ) {
-                       tool = this.tools[name];
-                       if ( !tool ) {
-                               // Auto-initialize tools on first use
-                               this.tools[name] = tool = toolFactory.create( name, this );
-                               tool.updateTitle();
-                       }
-                       this.toolbar.reserveTool( tool );
-                       add.push( tool );
-                       names[name] = true;
-               }
-       }
-       // Remove tools that are no longer needed
-       for ( name in this.tools ) {
-               if ( !names[name] ) {
-                       this.tools[name].destroy();
-                       this.toolbar.releaseTool( this.tools[name] );
-                       remove.push( this.tools[name] );
-                       delete this.tools[name];
-               }
-       }
-       if ( remove.length ) {
-               this.removeItems( remove );
-       }
-       // Update emptiness state
-       if ( add.length ) {
-               this.$element.removeClass( 'oo-ui-toolGroup-empty' );
-       } else {
-               this.$element.addClass( 'oo-ui-toolGroup-empty' );
-       }
-       // Re-add tools (moving existing ones to new locations)
-       this.addItems( add );
-};
-
-/**
- * Destroy tool group.
- *
- * @method
- */
-OO.ui.ToolGroup.prototype.destroy = function () {
-       var name;
-
-       this.clearItems();
-       this.toolbar.getToolFactory().disconnect( this );
-       for ( name in this.tools ) {
-               this.toolbar.releaseTool( this.tools[name] );
-               this.tools[name].disconnect( this ).destroy();
-               delete this.tools[name];
-       }
-       this.$element.remove();
-};
-/**
- * Layout made of a fieldset and optional legend.
- *
- * @class
- * @extends OO.ui.Layout
- * @mixins OO.ui.LabeledElement
- *
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {string} [icon] Symbolic icon name
- */
-OO.ui.FieldsetLayout = function OoUiFieldsetLayout( config ) {
-       // Config initialization
-       config = config || {};
-
-       // Parent constructor
-       OO.ui.Layout.call( this, config );
-
-       // Mixin constructors
-       OO.ui.LabeledElement.call( this, this.$( '<legend>' ), config );
-
-       // Initialization
-       if ( config.icon ) {
-               this.$element.addClass( 'oo-ui-fieldsetLayout-decorated' );
-               this.$label.addClass( 'oo-ui-icon-' + config.icon );
-       }
-       this.$element.addClass( 'oo-ui-fieldsetLayout' );
-       if ( config.icon || config.label ) {
-               this.$element
-                       .addClass( 'oo-ui-fieldsetLayout-labeled' )
-                       .append( this.$label );
-       }
-};
-
-/* Inheritance */
-
-OO.inheritClass( OO.ui.FieldsetLayout, OO.ui.Layout );
-
-OO.mixinClass( OO.ui.FieldsetLayout, OO.ui.LabeledElement );
-
-/* Static Properties */
-
-OO.ui.FieldsetLayout.static.tagName = 'fieldset';
-/**
- * Layout made of proportionally sized columns and rows.
- *
- * @class
- * @extends OO.ui.Layout
- *
- * @constructor
- * @param {OO.ui.PanelLayout[]} panels Panels in the grid
- * @param {Object} [config] Configuration options
- * @cfg {number[]} [widths] Widths of columns as ratios
- * @cfg {number[]} [heights] Heights of columns as ratios
- */
-OO.ui.GridLayout = function OoUiGridLayout( panels, config ) {
-       var i, len, widths;
-
-       // Config initialization
-       config = config || {};
-
-       // Parent constructor
-       OO.ui.Layout.call( this, config );
-
-       // Properties
-       this.panels = [];
-       this.widths = [];
-       this.heights = [];
-
-       // Initialization
-       this.$element.addClass( 'oo-ui-gridLayout' );
-       for ( i = 0, len = panels.length; i < len; i++ ) {
-               this.panels.push( panels[i] );
-               this.$element.append( panels[i].$element );
-       }
-       if ( config.widths || config.heights ) {
-               this.layout( config.widths || [1], config.heights || [1] );
-       } else {
-               // Arrange in columns by default
-               widths = [];
-               for ( i = 0, len = this.panels.length; i < len; i++ ) {
-                       widths[i] = 1;
-               }
-               this.layout( widths, [1] );
-       }
-};
-
-/* Inheritance */
-
-OO.inheritClass( OO.ui.GridLayout, OO.ui.Layout );
-
-/* Events */
-
-/**
- * @event layout
- */
-
-/**
- * @event update
- */
-
-/* Static Properties */
-
-OO.ui.GridLayout.static.tagName = 'div';
-
-/* Methods */
-
-/**
- * Set grid dimensions.
- *
- * @method
- * @param {number[]} widths Widths of columns as ratios
- * @param {number[]} heights Heights of rows as ratios
- * @fires layout
- * @throws {Error} If grid is not large enough to fit all panels
- */
-OO.ui.GridLayout.prototype.layout = function ( widths, heights ) {
-       var x, y,
-               xd = 0,
-               yd = 0,
-               cols = widths.length,
-               rows = heights.length;
-
-       // Verify grid is big enough to fit panels
-       if ( cols * rows < this.panels.length ) {
-               throw new Error( 'Grid is not large enough to fit ' + this.panels.length + 'panels' );
-       }
-
-       // Sum up denominators
-       for ( x = 0; x < cols; x++ ) {
-               xd += widths[x];
-       }
-       for ( y = 0; y < rows; y++ ) {
-               yd += heights[y];
-       }
-       // Store factors
-       this.widths = [];
-       this.heights = [];
-       for ( x = 0; x < cols; x++ ) {
-               this.widths[x] = widths[x] / xd;
-       }
-       for ( y = 0; y < rows; y++ ) {
-               this.heights[y] = heights[y] / yd;
-       }
-       // Synchronize view
-       this.update();
-       this.emit( 'layout' );
-};
-
-/**
- * Update panel positions and sizes.
- *
- * @method
- * @fires update
- */
-OO.ui.GridLayout.prototype.update = function () {
-       var x, y, panel,
-               i = 0,
-               left = 0,
-               top = 0,
-               dimensions,
-               width = 0,
-               height = 0,
-               cols = this.widths.length,
-               rows = this.heights.length;
-
-       for ( y = 0; y < rows; y++ ) {
-               for ( x = 0; x < cols; x++ ) {
-                       panel = this.panels[i];
-                       width = this.widths[x];
-                       height = this.heights[y];
-                       dimensions = {
-                               'width': Math.round( width * 100 ) + '%',
-                               'height': Math.round( height * 100 ) + '%',
-                               'top': Math.round( top * 100 ) + '%'
-                       };
-                       // If RTL, reverse:
-                       if ( OO.ui.Element.getDir( this.$.context ) === 'rtl' ) {
-                               dimensions.right = Math.round( left * 100 ) + '%';
-                       } else {
-                               dimensions.left = Math.round( left * 100 ) + '%';
-                       }
-                       panel.$element.css( dimensions );
-                       i++;
-                       left += width;
-               }
-               top += height;
-               left = 0;
-       }
-
-       this.emit( 'update' );
-};
-
-/**
- * Get a panel at a given position.
- *
- * The x and y position is affected by the current grid layout.
- *
- * @method
- * @param {number} x Horizontal position
- * @param {number} y Vertical position
- * @returns {OO.ui.PanelLayout} The panel at the given postion
- */
-OO.ui.GridLayout.prototype.getPanel = function ( x, y ) {
-       return this.panels[( x * this.widths.length ) + y];
-};
-/**
- * Layout containing a series of pages.
- *
- * @class
- * @extends OO.ui.Layout
- *
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {boolean} [continuous=false] Show all pages, one after another
- * @cfg {boolean} [autoFocus=false] Focus on the first focusable element when changing to a page
- * @cfg {boolean} [outlined=false] Show an outline
- * @cfg {boolean} [editable=false] Show controls for adding, removing and reordering pages
- * @cfg {Object[]} [adders] List of adders for controls, each with name, icon and title properties
- */
-OO.ui.BookletLayout = function OoUiBookletLayout( config ) {
-       // Initialize configuration
-       config = config || {};
-
-       // Parent constructor
-       OO.ui.Layout.call( this, config );
-
-       // Properties
-       this.currentPageName = null;
-       this.pages = {};
-       this.ignoreFocus = false;
-       this.stackLayout = new OO.ui.StackLayout( { '$': this.$, 'continuous': !!config.continuous } );
-       this.autoFocus = !!config.autoFocus;
-       this.outlined = !!config.outlined;
-       if ( this.outlined ) {
-               this.editable = !!config.editable;
-               this.adders = config.adders || null;
-               this.outlineControlsWidget = null;
-               this.outlineWidget = new OO.ui.OutlineWidget( { '$': this.$ } );
-               this.outlinePanel = new OO.ui.PanelLayout( { '$': this.$, 'scrollable': true } );
-               this.gridLayout = new OO.ui.GridLayout(
-                       [this.outlinePanel, this.stackLayout], { '$': this.$, 'widths': [1, 2] }
-               );
-               if ( this.editable ) {
-                       this.outlineControlsWidget = new OO.ui.OutlineControlsWidget(
-                               this.outlineWidget,
-                               { '$': this.$, 'adders': this.adders }
-                       );
-               }
-       }
-
-       // Events
-       this.stackLayout.connect( this, { 'set': 'onStackLayoutSet' } );
-       if ( this.outlined ) {
-               this.outlineWidget.connect( this, { 'select': 'onOutlineWidgetSelect' } );
-               // Event 'focus' does not bubble, but 'focusin' does
-               this.stackLayout.onDOMEvent( 'focusin', OO.ui.bind( this.onStackLayoutFocus, this ) );
-       }
-
-       // Initialization
-       this.$element.addClass( 'oo-ui-bookletLayout' );
-       this.stackLayout.$element.addClass( 'oo-ui-bookletLayout-stackLayout' );
-       if ( this.outlined ) {
-               this.outlinePanel.$element
-                       .addClass( 'oo-ui-bookletLayout-outlinePanel' )
-                       .append( this.outlineWidget.$element );
-               if ( this.editable ) {
-                       this.outlinePanel.$element
-                               .addClass( 'oo-ui-bookletLayout-outlinePanel-editable' )
-                               .append( this.outlineControlsWidget.$element );
-               }
-               this.$element.append( this.gridLayout.$element );
-       } else {
-               this.$element.append( this.stackLayout.$element );
-       }
-};
-
-/* Inheritance */
-
-OO.inheritClass( OO.ui.BookletLayout, OO.ui.Layout );
-
-/* Events */
-
-/**
- * @event set
- * @param {OO.ui.PageLayout} page Current page
- */
-
-/**
- * @event add
- * @param {OO.ui.PageLayout[]} page Added pages
- * @param {number} index Index pages were added at
- */
-
-/**
- * @event remove
- * @param {OO.ui.PageLayout[]} pages Removed pages
- */
-
-/* Methods */
-
-/**
- * Handle stack layout focus.
- *
- * @method
- * @param {jQuery.Event} e Focusin event
- */
-OO.ui.BookletLayout.prototype.onStackLayoutFocus = function ( e ) {
-       var name, $target;
-
-       if ( this.ignoreFocus ) {
-               // Avoid recursion from programmatic focus trigger in #onStackLayoutSet
-               return;
-       }
-
-       $target = $( e.target ).closest( '.oo-ui-pageLayout' );
-       for ( name in this.pages ) {
-               if ( this.pages[ name ].$element[0] === $target[0] ) {
-                       this.setPage( name );
-                       break;
-               }
-       }
-};
-
-/**
- * Handle stack layout set events.
- *
- * @method
- * @param {OO.ui.PanelLayout|null} page The page panel that is now the current panel
- */
-OO.ui.BookletLayout.prototype.onStackLayoutSet = function ( page ) {
-       if ( page ) {
-               page.scrollElementIntoView( { 'complete': OO.ui.bind( function () {
-                       this.ignoreFocus = true;
-                       if ( this.autoFocus ) {
-                               page.$element.find( ':input:first' ).focus();
-                       }
-                       this.ignoreFocus = false;
-               }, this ) } );
-       }
-};
-
-/**
- * Handle outline widget select events.
- *
- * @method
- * @param {OO.ui.OptionWidget|null} item Selected item
- */
-OO.ui.BookletLayout.prototype.onOutlineWidgetSelect = function ( item ) {
-       if ( item ) {
-               this.setPage( item.getData() );
-       }
-};
-
-/**
- * Check if booklet has an outline.
- *
- * @method
- * @returns {boolean} Booklet is outlined
- */
-OO.ui.BookletLayout.prototype.isOutlined = function () {
-       return this.outlined;
-};
-
-/**
- * Check if booklet has editing controls.
- *
- * @method
- * @returns {boolean} Booklet is outlined
- */
-OO.ui.BookletLayout.prototype.isEditable = function () {
-       return this.editable;
-};
-
-/**
- * Get the outline widget.
- *
- * @method
- * @returns {OO.ui.OutlineWidget|null} Outline widget, or null if boolet has no outline
- */
-OO.ui.BookletLayout.prototype.getOutline = function () {
-       return this.outlineWidget;
-};
-
-/**
- * Get the outline controls widget. If the outline is not editable, null is returned.
- *
- * @method
- * @returns {OO.ui.OutlineControlsWidget|null} The outline controls widget.
- */
-OO.ui.BookletLayout.prototype.getOutlineControls = function () {
-       return this.outlineControlsWidget;
-};
-
-/**
- * Get a page by name.
- *
- * @method
- * @param {string} name Symbolic name of page
- * @returns {OO.ui.PageLayout|undefined} Page, if found
- */
-OO.ui.BookletLayout.prototype.getPage = function ( name ) {
-       return this.pages[name];
-};
-
-/**
- * Get the current page name.
- *
- * @method
- * @returns {string|null} Current page name
- */
-OO.ui.BookletLayout.prototype.getPageName = function () {
-       return this.currentPageName;
-};
-
-/**
- * Add a page to the layout.
- *
- * When pages are added with the same names as existing pages, the existing pages will be
- * automatically removed before the new pages are added.
- *
- * @method
- * @param {OO.ui.PageLayout[]} pages Pages to add
- * @param {number} index Index to insert pages after
- * @fires add
- * @chainable
- */
-OO.ui.BookletLayout.prototype.addPages = function ( pages, index ) {
-       var i, len, name, page,
-               items = [],
-               remove = [];
-
-       for ( i = 0, len = pages.length; i < len; i++ ) {
-               page = pages[i];
-               name = page.getName();
-               if ( name in this.pages ) {
-                       // Remove page with same name
-                       remove.push( this.pages[name] );
-               }
-               this.pages[page.getName()] = page;
-               if ( this.outlined ) {
-                       items.push( new OO.ui.BookletOutlineItemWidget( name, page, { '$': this.$ } ) );
-               }
-       }
-       if ( remove.length ) {
-               this.removePages( remove );
-       }
-
-       if ( this.outlined && items.length ) {
-               this.outlineWidget.addItems( items, index );
-               this.updateOutlineWidget();
-       }
-       this.stackLayout.addItems( pages, index );
-       this.emit( 'add', pages, index );
-
-       return this;
-};
-
-/**
- * Remove a page from the layout.
- *
- * @method
- * @fires remove
- * @chainable
- */
-OO.ui.BookletLayout.prototype.removePages = function ( pages ) {
-       var i, len, name, page,
-               items = [];
-
-       for ( i = 0, len = pages.length; i < len; i++ ) {
-               page = pages[i];
-               name = page.getName();
-               delete this.pages[name];
-               if ( this.outlined ) {
-                       items.push( this.outlineWidget.getItemFromData( name ) );
-               }
-       }
-       if ( this.outlined && items.length ) {
-               this.outlineWidget.removeItems( items );
-               this.updateOutlineWidget();
-       }
-       this.stackLayout.removeItems( pages );
-       this.emit( 'remove', pages );
-
-       return this;
-};
-
-/**
- * Clear all pages from the layout.
- *
- * @method
- * @fires remove
- * @chainable
- */
-OO.ui.BookletLayout.prototype.clearPages = function () {
-       var pages = this.stackLayout.getItems();
-
-       this.pages = {};
-       this.currentPageName = null;
-       if ( this.outlined ) {
-               this.outlineWidget.clearItems();
-       }
-       this.stackLayout.clearItems();
-
-       this.emit( 'remove', pages );
-
-       return this;
-};
-
-/**
- * Set the current page by name.
- *
- * @method
- * @fires set
- * @param {string} name Symbolic name of page
- */
-OO.ui.BookletLayout.prototype.setPage = function ( name ) {
-       var selectedItem,
-               page = this.pages[name];
-
-       if ( this.outlined ) {
-               selectedItem = this.outlineWidget.getSelectedItem();
-               if ( selectedItem && selectedItem.getData() !== name ) {
-                       this.outlineWidget.selectItem( this.outlineWidget.getItemFromData( name ) );
-               }
-       }
-
-       if ( page ) {
-               this.currentPageName = name;
-               this.stackLayout.setItem( page );
-               this.emit( 'set', page );
-       }
-};
-
-/**
- * Call this after adding or removing items from the OutlineWidget.
- *
- * @method
- * @chainable
- */
-OO.ui.BookletLayout.prototype.updateOutlineWidget = function () {
-       // Auto-select first item when nothing is selected anymore
-       if ( !this.outlineWidget.getSelectedItem() ) {
-               this.outlineWidget.selectItem( this.outlineWidget.getFirstSelectableItem() );
-       }
-
-       return this;
-};
-/**
- * Layout that expands to cover the entire area of its parent, with optional scrolling and padding.
- *
- * @class
- * @extends OO.ui.Layout
- *
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {boolean} [scrollable] Allow vertical scrolling
- * @cfg {boolean} [padded] Pad the content from the edges
- */
-OO.ui.PanelLayout = function OoUiPanelLayout( config ) {
-       // Config initialization
-       config = config || {};
-
-       // Parent constructor
-       OO.ui.Layout.call( this, config );
-
-       // Initialization
-       this.$element.addClass( 'oo-ui-panelLayout' );
-       if ( config.scrollable ) {
-               this.$element.addClass( 'oo-ui-panelLayout-scrollable' );
-       }
-
-       if ( config.padded ) {
-               this.$element.addClass( 'oo-ui-panelLayout-padded' );
-       }
-
-       // Add directionality class:
-       this.$element.addClass( 'oo-ui-' + OO.ui.Element.getDir( this.$.context ) );
-};
-
-/* Inheritance */
-
-OO.inheritClass( OO.ui.PanelLayout, OO.ui.Layout );
-/**
- * Page within an OO.ui.BookletLayout.
- *
- * @class
- * @extends OO.ui.PanelLayout
- *
- * @constructor
- * @param {string} name Unique symbolic name of page
- * @param {Object} [config] Configuration options
- * @param {string} [icon=''] Symbolic name of icon to display in outline
- * @param {string} [indicator=''] Symbolic name of indicator to display in outline
- * @param {string} [indicatorTitle=''] Description of indicator meaning to display in outline
- * @param {string} [label=''] Label to display in outline
- * @param {number} [level=0] Indentation level of item in outline
- * @param {boolean} [movable=false] Page should be movable using outline controls
- */
-OO.ui.PageLayout = function OoUiPageLayout( name, config ) {
-       // Configuration initialization
-       config = $.extend( { 'scrollable': true }, config );
-
-       // Parent constructor
-       OO.ui.PanelLayout.call( this, config );
-
-       // Properties
-       this.name = name;
-       this.icon = config.icon || '';
-       this.indicator = config.indicator || '';
-       this.indicatorTitle = OO.ui.resolveMsg( config.indicatorTitle ) || '';
-       this.label = OO.ui.resolveMsg( config.label ) || '';
-       this.level = config.level || 0;
-       this.movable = !!config.movable;
-
-       // Initialization
-       this.$element.addClass( 'oo-ui-pageLayout' );
-};
-
-/* Inheritance */
-
-OO.inheritClass( OO.ui.PageLayout, OO.ui.PanelLayout );
-
-/* Methods */
-
-/**
- * Get page name.
- *
- * @returns {string} Symbolic name of page
- */
-OO.ui.PageLayout.prototype.getName = function () {
-       return this.name;
-};
-
-/**
- * Get page icon.
- *
- * @returns {string} Symbolic name of icon
- */
-OO.ui.PageLayout.prototype.getIcon = function () {
-       return this.icon;
-};
-
-/**
- * Get page indicator.
- *
- * @returns {string} Symbolic name of indicator
- */
-OO.ui.PageLayout.prototype.getIndicator = function () {
-       return this.indicator;
-};
-
-/**
- * Get page indicator label.
- *
- * @returns {string} Description of indicator meaning
- */
-OO.ui.PageLayout.prototype.getIndicatorTitle = function () {
-       return this.indicatorTitle;
-};
-
-/**
- * Get page label.
- *
- * @returns {string} Label text
- */
-OO.ui.PageLayout.prototype.getLabel = function () {
-       return this.label;
-};
-
-/**
- * Get outline item indentation level.
- *
- * @returns {number} Indentation level
- */
-OO.ui.PageLayout.prototype.getLevel = function () {
-       return this.level;
-};
-
-/**
- * Check if page is movable using outline controls.
- *
- * @returns {boolean} Page is movable
- */
-OO.ui.PageLayout.prototype.isMovable = function () {
-       return this.movable;
-};
-/**
- * Layout containing a series of mutually exclusive pages.
- *
- * @class
- * @extends OO.ui.PanelLayout
- * @mixins OO.ui.GroupElement
- *
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {boolean} [continuous=false] Show all pages, one after another
- * @cfg {string} [icon=''] Symbolic icon name
- */
-OO.ui.StackLayout = function OoUiStackLayout( config ) {
-       // Config initialization
-       config = $.extend( { 'scrollable': true }, config );
-
-       // Parent constructor
-       OO.ui.PanelLayout.call( this, config );
-
-       // Mixin constructors
-       OO.ui.GroupElement.call( this, this.$element, config );
-
-       // Properties
-       this.currentItem = null;
-       this.continuous = !!config.continuous;
-
-       // Initialization
-       this.$element.addClass( 'oo-ui-stackLayout' );
-       if ( this.continuous ) {
-               this.$element.addClass( 'oo-ui-stackLayout-continuous' );
-       }
-};
-
-/* Inheritance */
-
-OO.inheritClass( OO.ui.StackLayout, OO.ui.PanelLayout );
-
-OO.mixinClass( OO.ui.StackLayout, OO.ui.GroupElement );
-
-/* Events */
-
-/**
- * @event set
- * @param {OO.ui.PanelLayout|null} [item] Current item
- */
-
-/* Methods */
-
-/**
- * Add items.
- *
- * Adding an existing item (by value) will move it.
- *
- * @method
- * @param {OO.ui.PanelLayout[]} items Items to add
- * @param {number} [index] Index to insert items after
- * @chainable
- */
-OO.ui.StackLayout.prototype.addItems = function ( items, index ) {
-       OO.ui.GroupElement.prototype.addItems.call( this, items, index );
-
-       if ( !this.currentItem && items.length ) {
-               this.setItem( items[0] );
-       }
-
-       return this;
-};
-
-/**
- * Remove items.
- *
- * Items will be detached, not removed, so they can be used later.
- *
- * @method
- * @param {OO.ui.PanelLayout[]} items Items to remove
- * @chainable
- */
-OO.ui.StackLayout.prototype.removeItems = function ( items ) {
-       OO.ui.GroupElement.prototype.removeItems.call( this, items );
-       if ( items.indexOf( this.currentItem ) !== -1 ) {
-               this.currentItem = null;
-               if ( !this.currentItem && this.items.length ) {
-                       this.setItem( this.items[0] );
-               }
-       }
-
-       return this;
-};
-
-/**
- * Clear all items.
- *
- * Items will be detached, not removed, so they can be used later.
- *
- * @method
- * @chainable
- */
-OO.ui.StackLayout.prototype.clearItems = function () {
-       this.currentItem = null;
-       OO.ui.GroupElement.prototype.clearItems.call( this );
-
-       return this;
-};
-
-/**
- * Show item.
- *
- * Any currently shown item will be hidden.
- *
- * @method
- * @param {OO.ui.PanelLayout} item Item to show
- * @chainable
- */
-OO.ui.StackLayout.prototype.setItem = function ( item ) {
-       if ( !this.continuous ) {
-               this.$items.css( 'display', '' );
-       }
-       if ( this.items.indexOf( item ) !== -1 ) {
-               if ( !this.continuous ) {
-                       item.$element.css( 'display', 'block' );
-               }
-       } else {
-               item = null;
-       }
-       this.currentItem = item;
-       this.emit( 'set', item );
-
-       return this;
-};
-/**
- * Horizontal bar layout of tools as icon buttons.
- *
- * @class
- * @abstract
- * @extends OO.ui.ToolGroup
- *
- * @constructor
- * @param {OO.ui.Toolbar} toolbar
- * @param {Object} [config] Configuration options
- */
-OO.ui.BarToolGroup = function OoUiBarToolGroup( toolbar, config ) {
-       // Parent constructor
-       OO.ui.ToolGroup.call( this, toolbar, config );
-
-       // Initialization
-       this.$element.addClass( 'oo-ui-barToolGroup' );
-};
-
-/* Inheritance */
-
-OO.inheritClass( OO.ui.BarToolGroup, OO.ui.ToolGroup );
-
-/* Static Properties */
-
-OO.ui.BarToolGroup.static.titleTooltips = true;
-
-OO.ui.BarToolGroup.static.accelTooltips = true;
-/**
- * Popup list of tools with an icon and optional label.
- *
- * @class
- * @abstract
- * @extends OO.ui.ToolGroup
- * @mixins OO.ui.IconedElement
- * @mixins OO.ui.IndicatedElement
- * @mixins OO.ui.LabeledElement
- * @mixins OO.ui.TitledElement
- * @mixins OO.ui.ClippableElement
- *
- * @constructor
- * @param {OO.ui.Toolbar} toolbar
- * @param {Object} [config] Configuration options
- */
-OO.ui.PopupToolGroup = function OoUiPopupToolGroup( toolbar, config ) {
-       // Configuration initialization
-       config = config || {};
-
-       // Parent constructor
-       OO.ui.ToolGroup.call( this, toolbar, config );
-
-       // Mixin constructors
-       OO.ui.IconedElement.call( this, this.$( '<span>' ), config );
-       OO.ui.IndicatedElement.call( this, this.$( '<span>' ), config );
-       OO.ui.LabeledElement.call( this, this.$( '<span>' ), config );
-       OO.ui.TitledElement.call( this, this.$element, config );
-       OO.ui.ClippableElement.call( this, this.$group );
-
-       // Properties
-       this.active = false;
-       this.dragging = false;
-       this.onBlurHandler = OO.ui.bind( this.onBlur, this );
-       this.$handle = this.$( '<span>' );
-
-       // Events
-       this.$handle.on( {
-               'mousedown': OO.ui.bind( this.onHandleMouseDown, this ),
-               'mouseup': OO.ui.bind( this.onHandleMouseUp, this )
-       } );
-
-       // Initialization
-       this.$handle
-               .addClass( 'oo-ui-popupToolGroup-handle' )
-               .append( this.$icon, this.$label, this.$indicator );
-       this.$element
-               .addClass( 'oo-ui-popupToolGroup' )
-               .prepend( this.$handle );
-};
-
-/* Inheritance */
-
-OO.inheritClass( OO.ui.PopupToolGroup, OO.ui.ToolGroup );
-
-OO.mixinClass( OO.ui.PopupToolGroup, OO.ui.IconedElement );
-OO.mixinClass( OO.ui.PopupToolGroup, OO.ui.IndicatedElement );
-OO.mixinClass( OO.ui.PopupToolGroup, OO.ui.LabeledElement );
-OO.mixinClass( OO.ui.PopupToolGroup, OO.ui.TitledElement );
-OO.mixinClass( OO.ui.PopupToolGroup, OO.ui.ClippableElement );
-
-/* Static Properties */
-
-/* Methods */
-
-/**
- * Handle focus being lost.
- *
- * The event is actually generated from a mouseup, so it is not a normal blur event object.
- *
- * @method
- * @param {jQuery.Event} e Mouse up event
- */
-OO.ui.PopupToolGroup.prototype.onBlur = function ( e ) {
-       // Only deactivate when clicking outside the dropdown element
-       if ( this.$( e.target ).closest( '.oo-ui-popupToolGroup' )[0] !== this.$element[0] ) {
-               this.setActive( false );
-       }
-};
-
-/**
- * @inheritdoc
- */
-OO.ui.PopupToolGroup.prototype.onMouseUp = function ( e ) {
-       this.setActive( false );
-       return OO.ui.ToolGroup.prototype.onMouseUp.call( this, e );
-};
-
-/**
- * @inheritdoc
- */
-OO.ui.PopupToolGroup.prototype.onMouseDown = function ( e ) {
-       return OO.ui.ToolGroup.prototype.onMouseDown.call( this, e );
-};
-
-/**
- * Handle mouse up events.
- *
- * @method
- * @param {jQuery.Event} e Mouse up event
- */
-OO.ui.PopupToolGroup.prototype.onHandleMouseUp = function () {
-       return false;
-};
-
-/**
- * Handle mouse down events.
- *
- * @method
- * @param {jQuery.Event} e Mouse down event
- */
-OO.ui.PopupToolGroup.prototype.onHandleMouseDown = function ( e ) {
-       if ( !this.disabled && e.which === 1 ) {
-               this.setActive( !this.active );
-       }
-       return false;
-};
-
-/**
- * Switch into active mode.
- *
- * When active, mouseup events anywhere in the document will trigger deactivation.
- *
- * @method
- */
-OO.ui.PopupToolGroup.prototype.setActive = function ( value ) {
-       value = !!value;
-       if ( this.active !== value ) {
-               this.active = value;
-               if ( value ) {
-                       this.setClipping( true );
-                       this.$element.addClass( 'oo-ui-popupToolGroup-active' );
-                       this.getElementDocument().addEventListener( 'mouseup', this.onBlurHandler, true );
-               } else {
-                       this.setClipping( false );
-                       this.$element.removeClass( 'oo-ui-popupToolGroup-active' );
-                       this.getElementDocument().removeEventListener( 'mouseup', this.onBlurHandler, true );
-               }
-       }
-};
-/**
- * Drop down list layout of tools as labeled icon buttons.
- *
- * @class
- * @abstract
- * @extends OO.ui.PopupToolGroup
- *
- * @constructor
- * @param {OO.ui.Toolbar} toolbar
- * @param {Object} [config] Configuration options
- */
-OO.ui.ListToolGroup = function OoUiListToolGroup( toolbar, config ) {
-       // Parent constructor
-       OO.ui.PopupToolGroup.call( this, toolbar, config );
-
-       // Initialization
-       this.$element.addClass( 'oo-ui-listToolGroup' );
-};
-
-/* Inheritance */
-
-OO.inheritClass( OO.ui.ListToolGroup, OO.ui.PopupToolGroup );
-
-/* Static Properties */
-
-OO.ui.ListToolGroup.static.accelTooltips = true;
-/**
- * Drop down menu layout of tools as selectable menu items.
- *
- * @class
- * @abstract
- * @extends OO.ui.PopupToolGroup
- *
- * @constructor
- * @param {OO.ui.Toolbar} toolbar
- * @param {Object} [config] Configuration options
- */
-OO.ui.MenuToolGroup = function OoUiMenuToolGroup( toolbar, config ) {
-       // Configuration initialization
-       config = config || {};
-
-       // Parent constructor
-       OO.ui.PopupToolGroup.call( this, toolbar, config );
-
-       // Events
-       this.toolbar.connect( this, { 'updateState': 'onUpdateState' } );
-
-       // Initialization
-       this.$element.addClass( 'oo-ui-menuToolGroup' );
-};
-
-/* Inheritance */
-
-OO.inheritClass( OO.ui.MenuToolGroup, OO.ui.PopupToolGroup );
-
-/* Static Properties */
-
-OO.ui.MenuToolGroup.static.accelTooltips = true;
-
-/* Methods */
-
-/**
- * Handle the toolbar state being updated.
- *
- * When the state changes, the title of each active item in the menu will be joined together and
- * used as a label for the group. The label will be empty if none of the items are active.
- *
- * @method
- */
-OO.ui.MenuToolGroup.prototype.onUpdateState = function () {
-       var name,
-               labelTexts = [];
-
-       for ( name in this.tools ) {
-               if ( this.tools[name].isActive() ) {
-                       labelTexts.push( this.tools[name].getTitle() );
-               }
-       }
-
-       this.setLabel( labelTexts.join( ', ' ) );
-};
-/**
- * UserInterface popup tool.
- *
- * @abstract
- * @class
- * @extends OO.ui.Tool
- * @mixins OO.ui.PopuppableElement
- *
- * @constructor
- * @param {OO.ui.Toolbar} toolbar
- * @param {Object} [config] Configuration options
- */
-OO.ui.PopupTool = function OoUiPopupTool( toolbar, config ) {
-       // Parent constructor
-       OO.ui.Tool.call( this, toolbar, config );
-
-       // Mixin constructors
-       OO.ui.PopuppableElement.call( this, config );
-
-       // Initialization
-       this.$element
-               .addClass( 'oo-ui-popupTool' )
-               .append( this.popup.$element );
-};
-
-/* Inheritance */
-
-OO.inheritClass( OO.ui.PopupTool, OO.ui.Tool );
-
-OO.mixinClass( OO.ui.PopupTool, OO.ui.PopuppableElement );
-
-/* Methods */
-
-/**
- * Handle the tool being selected.
- *
- * @inheritdoc
- */
-OO.ui.PopupTool.prototype.onSelect = function () {
-       if ( !this.disabled ) {
-               if ( this.popup.isVisible() ) {
-                       this.hidePopup();
-               } else {
-                       this.showPopup();
-               }
-       }
-       this.setActive( false );
-       return false;
-};
-
-/**
- * Handle the toolbar state being updated.
- *
- * @inheritdoc
- */
-OO.ui.PopupTool.prototype.onUpdateState = function () {
-       this.setActive( false );
-};
-/**
- * Container for multiple related buttons.
- *
- * @class
- * @extends OO.ui.Widget
- * @mixin OO.ui.GroupElement
- *
- * @constructor
- * @param {Object} [config] Configuration options
- */
-OO.ui.ButtonGroupWidget = function OoUiButtonGroupWidget( config ) {
-       // Parent constructor
-       OO.ui.Widget.call( this, config );
-
-       // Mixin constructors
-       OO.ui.GroupElement.call( this, this.$element, config );
-
-       // Initialization
-       this.$element.addClass( 'oo-ui-buttonGroupWidget' );
-};
-
-/* Inheritance */
-
-OO.inheritClass( OO.ui.ButtonGroupWidget, OO.ui.Widget );
-
-OO.mixinClass( OO.ui.ButtonGroupWidget, OO.ui.GroupElement );
-/**
- * Creates an OO.ui.ButtonWidget object.
- *
- * @class
- * @abstract
- * @extends OO.ui.Widget
- * @mixins OO.ui.ButtonedElement
- * @mixins OO.ui.IconedElement
- * @mixins OO.ui.IndicatedElement
- * @mixins OO.ui.LabeledElement
- * @mixins OO.ui.TitledElement
- * @mixins OO.ui.FlaggableElement
- *
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {string} [title=''] Title text
- * @cfg {string} [href] Hyperlink to visit when clicked
- * @cfg {string} [target] Target to open hyperlink in
- */
-OO.ui.ButtonWidget = function OoUiButtonWidget( config ) {
-       // Configuration initialization
-       config = $.extend( { 'target': '_blank' }, config );
-
-       // Parent constructor
-       OO.ui.Widget.call( this, config );
-
-       // Mixin constructors
-       OO.ui.ButtonedElement.call( this, this.$( '<a>' ), config );
-       OO.ui.IconedElement.call( this, this.$( '<span>' ), config );
-       OO.ui.IndicatedElement.call( this, this.$( '<span>' ), config );
-       OO.ui.LabeledElement.call( this, this.$( '<span>' ), config );
-       OO.ui.TitledElement.call( this, this.$button, config );
-       OO.ui.FlaggableElement.call( this, config );
-
-       // Properties
-       this.isHyperlink = typeof config.href === 'string';
-
-       // Events
-       this.$button.on( {
-               'click': OO.ui.bind( this.onClick, this ),
-               'keypress': OO.ui.bind( this.onKeyPress, this )
-       } );
-
-       // Initialization
-       this.$button
-               .append( this.$icon, this.$label, this.$indicator )
-               .attr( { 'href': config.href, 'target': config.target } );
-       this.$element
-               .addClass( 'oo-ui-buttonWidget' )
-               .append( this.$button );
-};
-
-/* Inheritance */
-
-OO.inheritClass( OO.ui.ButtonWidget, OO.ui.Widget );
-
-OO.mixinClass( OO.ui.ButtonWidget, OO.ui.ButtonedElement );
-OO.mixinClass( OO.ui.ButtonWidget, OO.ui.IconedElement );
-OO.mixinClass( OO.ui.ButtonWidget, OO.ui.IndicatedElement );
-OO.mixinClass( OO.ui.ButtonWidget, OO.ui.LabeledElement );
-OO.mixinClass( OO.ui.ButtonWidget, OO.ui.TitledElement );
-OO.mixinClass( OO.ui.ButtonWidget, OO.ui.FlaggableElement );
-
-/* Events */
-
-/**
- * @event click
- */
-
-/* Methods */
-
-/**
- * Handles mouse click events.
- *
- * @method
- * @param {jQuery.Event} e Mouse click event
- * @fires click
- */
-OO.ui.ButtonWidget.prototype.onClick = function () {
-       if ( !this.disabled ) {
-               this.emit( 'click' );
-               if ( this.isHyperlink ) {
-                       return true;
-               }
-       }
-       return false;
-};
-
-/**
- * Handles keypress events.
- *
- * @method
- * @param {jQuery.Event} e Keypress event
- * @fires click
- */
-OO.ui.ButtonWidget.prototype.onKeyPress = function ( e ) {
-       if ( !this.disabled && e.which === OO.ui.Keys.SPACE ) {
-               if ( this.isHyperlink ) {
-                       this.onClick();
-                       return true;
-               }
-       }
-       return false;
-};
-/**
- * Creates an OO.ui.InputWidget object.
- *
- * @class
- * @abstract
- * @extends OO.ui.Widget
- *
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {string} [name=''] HTML input name
- * @cfg {string} [value=''] Input value
- * @cfg {boolean} [readOnly=false] Prevent changes
- * @cfg {Function} [inputFilter] Filter function to apply to the input. Takes a string argument and returns a string.
- */
-OO.ui.InputWidget = function OoUiInputWidget( config ) {
-       // Config intialization
-       config = $.extend( { 'readOnly': false }, config );
-
-       // Parent constructor
-       OO.ui.Widget.call( this, config );
-
-       // Properties
-       this.$input = this.getInputElement( config );
-       this.value = '';
-       this.readOnly = false;
-       this.inputFilter = config.inputFilter;
-
-       // Events
-       this.$input.on( 'keydown mouseup cut paste change input select', OO.ui.bind( this.onEdit, this ) );
-
-       // Initialization
-       this.$input
-               .attr( 'name', config.name )
-               .prop( 'disabled', this.disabled );
-       this.setReadOnly( config.readOnly );
-       this.$element.addClass( 'oo-ui-inputWidget' ).append( this.$input );
-       this.setValue( config.value );
-};
-
-/* Inheritance */
-
-OO.inheritClass( OO.ui.InputWidget, OO.ui.Widget );
-
-/* Events */
-
-/**
- * @event change
- * @param value
- */
-
-/* Methods */
-
-/**
- * Get input element.
- *
- * @method
- * @param {Object} [config] Configuration options
- * @returns {jQuery} Input element
- */
-OO.ui.InputWidget.prototype.getInputElement = function () {
-       return this.$( '<input>' );
-};
-
-/**
- * Handle potentially value-changing events.
- *
- * @method
- * @param {jQuery.Event} e Key down, mouse up, cut, paste, change, input, or select event
- */
-OO.ui.InputWidget.prototype.onEdit = function () {
-       if ( !this.disabled ) {
-               // Allow the stack to clear so the value will be updated
-               setTimeout( OO.ui.bind( function () {
-                       this.setValue( this.$input.val() );
-               }, this ) );
-       }
-};
-
-/**
- * Get the value of the input.
- *
- * @method
- * @returns {string} Input value
- */
-OO.ui.InputWidget.prototype.getValue = function () {
-       return this.value;
-};
-
-/**
- * Sets the direction of the current input, either RTL or LTR
- *
- * @method
- * @param {boolean} isRTL
- */
-OO.ui.InputWidget.prototype.setRTL = function ( isRTL ) {
-       if ( isRTL ) {
-               this.$input.removeClass( 'oo-ui-ltr' );
-               this.$input.addClass( 'oo-ui-rtl' );
-       } else {
-               this.$input.removeClass( 'oo-ui-rtl' );
-               this.$input.addClass( 'oo-ui-ltr' );
-       }
-};
-
-/**
- * Set the value of the input.
- *
- * @method
- * @param {string} value New value
- * @fires change
- * @chainable
- */
-OO.ui.InputWidget.prototype.setValue = function ( value ) {
-       value = this.sanitizeValue( value );
-       if ( this.value !== value ) {
-               this.value = value;
-               this.emit( 'change', this.value );
-       }
-       // Update the DOM if it has changed. Note that with sanitizeValue, it
-       // is possible for the DOM value to change without this.value changing.
-       if ( this.$input.val() !== this.value ) {
-               this.$input.val( this.value );
-       }
-       return this;
-};
-
-/**
- * Sanitize incoming value.
- *
- * Ensures value is a string, and converts undefined and null to empty strings.
- *
- * @method
- * @param {string} value Original value
- * @returns {string} Sanitized value
- */
-OO.ui.InputWidget.prototype.sanitizeValue = function ( value ) {
-       if ( value === undefined || value === null ) {
-               return '';
-       } else if ( this.inputFilter ) {
-               return this.inputFilter( String( value ) );
-       } else {
-               return String( value );
-       }
-};
-
-/**
- * Check if the widget is read-only.
- *
- * @method
- * @param {boolean} Input is read-only
- */
-OO.ui.InputWidget.prototype.isReadOnly = function () {
-       return this.readOnly;
-};
-
-/**
- * Set the read-only state of the widget.
- *
- * This should probably change the widgets's appearance and prevent it from being used.
- *
- * @method
- * @param {boolean} state Make input read-only
- * @chainable
- */
-OO.ui.InputWidget.prototype.setReadOnly = function ( state ) {
-       this.readOnly = !!state;
-       this.$input.prop( 'readonly', this.readOnly );
-       return this;
-};
-
-/**
- * @inheritdoc
- */
-OO.ui.InputWidget.prototype.setDisabled = function ( state ) {
-       OO.ui.Widget.prototype.setDisabled.call( this, state );
-       if ( this.$input ) {
-               this.$input.prop( 'disabled', this.disabled );
-       }
-       return this;
-};/**
- * Creates an OO.ui.CheckboxInputWidget object.
- *
- * @class
- * @extends OO.ui.InputWidget
- *
- * @constructor
- * @param {Object} [config] Configuration options
- */
-OO.ui.CheckboxInputWidget = function OoUiCheckboxInputWidget( config ) {
-       // Parent constructor
-       OO.ui.InputWidget.call( this, config );
-
-       // Initialization
-       this.$element.addClass( 'oo-ui-checkboxInputWidget' );
-};
-
-/* Inheritance */
-
-OO.inheritClass( OO.ui.CheckboxInputWidget, OO.ui.InputWidget );
-
-/* Events */
-
-/* Methods */
-
-/**
- * Get input element.
- *
- * @returns {jQuery} Input element
- */
-OO.ui.CheckboxInputWidget.prototype.getInputElement = function () {
-       return this.$( '<input type="checkbox" />' );
-};
-
-/**
- * Get checked state of the checkbox
- *
- * @returns {boolean} If the checkbox is checked
- */
-OO.ui.CheckboxInputWidget.prototype.getValue = function () {
-       return this.value;
-};
-
-/**
- * Set value
- */
-OO.ui.CheckboxInputWidget.prototype.setValue = function ( value ) {
-       value = !!value;
-       if ( this.value !== value ) {
-               this.value = value;
-               this.$input.prop( 'checked', this.value );
-               this.emit( 'change', this.value );
-       }
-};
-
-/**
- * @inheritdoc
- */
-OO.ui.CheckboxInputWidget.prototype.onEdit = function () {
-       if ( !this.disabled ) {
-               // Allow the stack to clear so the value will be updated
-               setTimeout( OO.ui.bind( function () {
-                       this.setValue( this.$input.prop( 'checked' ) );
-               }, this ) );
-       }
-};
-/**
- * Creates an OO.ui.CheckboxWidget object.
- *
- * @class
- * @extends OO.ui.CheckboxInputWidget
- * @mixins OO.ui.LabeledElement
- *
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {string} [label=''] Label
- */
-OO.ui.CheckboxWidget = function OoUiCheckboxWidget( config ) {
-       // Configuration initialization
-       config = config || {};
-
-       // Parent constructor
-       OO.ui.CheckboxInputWidget.call( this, config );
-
-       // Mixin constructors
-       OO.ui.LabeledElement.call( this, this.$( '<span>' ) , config );
-
-       // Initialization
-       this.$element
-               .addClass( 'oo-ui-checkboxWidget' )
-               .append( this.$( '<label>' ).append( this.$input, this.$label ) );
-};
-
-/* Inheritance */
-
-OO.inheritClass( OO.ui.CheckboxWidget, OO.ui.CheckboxInputWidget );
-
-OO.mixinClass( OO.ui.CheckboxWidget, OO.ui.LabeledElement );
-/**
- * Creates an OO.ui.InputLabelWidget object.
- *
- * CSS classes will be added to the button for each flag, each prefixed with 'oo-ui-InputLabelWidget-'
- *
- * @class
- * @extends OO.ui.Widget
- * @mixins OO.ui.LabeledElement
- *
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {OO.ui.InputWidget|null} [input] Related input widget
- */
-OO.ui.InputLabelWidget = function OoUiInputLabelWidget( config ) {
-       // Config intialization
-       config = $.extend( { 'input': null }, config );
-
-       // Parent constructor
-       OO.ui.Widget.call( this, config );
-
-       // Mixin constructors
-       OO.ui.LabeledElement.call( this, this.$element, config );
-
-       // Properties
-       this.input = config.input;
-
-       // Events
-       this.$element.on( 'click', OO.ui.bind( this.onClick, this ) );
-
-       // Initialization
-       this.$element.addClass( 'oo-ui-inputLabelWidget' );
-};
-
-/* Inheritance */
-
-OO.inheritClass( OO.ui.InputLabelWidget, OO.ui.Widget );
-
-OO.mixinClass( OO.ui.InputLabelWidget, OO.ui.LabeledElement );
-
-/* Static Properties */
-
-OO.ui.InputLabelWidget.static.tagName = 'label';
-
-/* Methods */
-
-/**
- * Handles mouse click events.
- *
- * @method
- * @param {jQuery.Event} e Mouse click event
- */
-OO.ui.InputLabelWidget.prototype.onClick = function () {
-       if ( !this.disabled && this.input ) {
-               this.input.$input.focus();
-       }
-       return false;
-};
-/**
- * Lookup input widget.
- *
- * Mixin that adds a menu showing suggested values to a text input. Subclasses must handle `select`
- * events on #lookupMenu to make use of selections.
- *
- * @class
- * @abstract
- *
- * @constructor
- * @param {OO.ui.TextInputWidget} input Input widget
- * @param {Object} [config] Configuration options
- * @cfg {jQuery} [$overlay=this.$( 'body' )] Overlay layer
- */
-OO.ui.LookupInputWidget = function OoUiLookupInputWidget( input, config ) {
-       // Config intialization
-       config = config || {};
-
-       // Properties
-       this.lookupInput = input;
-       this.$overlay = config.$overlay || this.$( 'body,.oo-ui-window-overlay' ).last();
-       this.lookupMenu = new OO.ui.TextInputMenuWidget( this, {
-               '$': OO.ui.Element.getJQuery( this.$overlay ),
-               'input': this.lookupInput,
-               '$container': config.$container
-       } );
-       this.lookupCache = {};
-       this.lookupQuery = null;
-       this.lookupRequest = null;
-       this.populating = false;
-
-       // Events
-       this.$overlay.append( this.lookupMenu.$element );
-
-       this.lookupInput.$input.on( {
-               'focus': OO.ui.bind( this.onLookupInputFocus, this ),
-               'blur': OO.ui.bind( this.onLookupInputBlur, this ),
-               'mousedown': OO.ui.bind( this.onLookupInputMouseDown, this )
-       } );
-       this.lookupInput.connect( this, { 'change': 'onLookupInputChange' } );
-
-       // Initialization
-       this.$element.addClass( 'oo-ui-lookupWidget' );
-       this.lookupMenu.$element.addClass( 'oo-ui-lookupWidget-menu' );
-};
-
-/* Methods */
-
-/**
- * Handle input focus event.
- *
- * @method
- * @param {jQuery.Event} e Input focus event
- */
-OO.ui.LookupInputWidget.prototype.onLookupInputFocus = function () {
-       this.openLookupMenu();
-};
-
-/**
- * Handle input blur event.
- *
- * @method
- * @param {jQuery.Event} e Input blur event
- */
-OO.ui.LookupInputWidget.prototype.onLookupInputBlur = function () {
-       this.lookupMenu.hide();
-};
-
-/**
- * Handle input mouse down event.
- *
- * @method
- * @param {jQuery.Event} e Input mouse down event
- */
-OO.ui.LookupInputWidget.prototype.onLookupInputMouseDown = function () {
-       this.openLookupMenu();
-};
-
-/**
- * Handle input change event.
- *
- * @method
- * @param {string} value New input value
- */
-OO.ui.LookupInputWidget.prototype.onLookupInputChange = function () {
-       this.openLookupMenu();
-};
-
-/**
- * Open the menu.
- *
- * @method
- * @chainable
- */
-OO.ui.LookupInputWidget.prototype.openLookupMenu = function () {
-       var value = this.lookupInput.getValue();
-
-       if ( this.lookupMenu.$input.is( ':focus' ) && $.trim( value ) !== '' ) {
-               this.populateLookupMenu();
-               if ( !this.lookupMenu.isVisible() ) {
-                       this.lookupMenu.show();
-               }
-       } else {
-               this.lookupMenu.clearItems();
-               this.lookupMenu.hide();
-       }
-
-       return this;
-};
-
-/**
- * Populate lookup menu with current information.
- *
- * @method
- * @chainable
- */
-OO.ui.LookupInputWidget.prototype.populateLookupMenu = function () {
-       if ( !this.populating ) {
-               this.populating = true;
-               this.getLookupMenuItems()
-                       .done( OO.ui.bind( function ( items ) {
-                               this.lookupMenu.clearItems();
-                               if ( items.length ) {
-                                       this.lookupMenu.show();
-                                       this.lookupMenu.addItems( items );
-                                       this.initializeLookupMenuSelection();
-                                       this.openLookupMenu();
-                               } else {
-                                       this.lookupMenu.hide();
-                               }
-                               this.populating = false;
-                       }, this ) )
-                       .fail( OO.ui.bind( function () {
-                               this.lookupMenu.clearItems();
-                               this.populating = false;
-                       }, this ) );
-       }
-
-       return this;
-};
-
-/**
- * Set selection in the lookup menu with current information.
- *
- * @method
- * @chainable
- */
-OO.ui.LookupInputWidget.prototype.initializeLookupMenuSelection = function () {
-       if ( !this.lookupMenu.getSelectedItem() ) {
-               this.lookupMenu.intializeSelection( this.lookupMenu.getFirstSelectableItem() );
-       }
-       this.lookupMenu.highlightItem( this.lookupMenu.getSelectedItem() );
-};
-
-/**
- * Get lookup menu items for the current query.
- *
- * @method
- * @returns {jQuery.Promise} Promise object which will be passed menu items as the first argument
- * of the done event
- */
-OO.ui.LookupInputWidget.prototype.getLookupMenuItems = function () {
-       var value = this.lookupInput.getValue(),
-               deferred = $.Deferred();
-
-       if ( value && value !== this.lookupQuery ) {
-               // Abort current request if query has changed
-               if ( this.lookupRequest ) {
-                       this.lookupRequest.abort();
-                       this.lookupQuery = null;
-                       this.lookupRequest = null;
-               }
-               if ( value in this.lookupCache ) {
-                       deferred.resolve( this.getLookupMenuItemsFromData( this.lookupCache[value] ) );
-               } else {
-                       this.lookupQuery = value;
-                       this.lookupRequest = this.getLookupRequest()
-                               .always( OO.ui.bind( function () {
-                                       this.lookupQuery = null;
-                                       this.lookupRequest = null;
-                               }, this ) )
-                               .done( OO.ui.bind( function ( data ) {
-                                       this.lookupCache[value] = this.getLookupCacheItemFromData( data );
-                                       deferred.resolve( this.getLookupMenuItemsFromData( this.lookupCache[value] ) );
-                               }, this ) )
-                               .fail( function () {
-                                       deferred.reject();
-                               } );
-                       this.pushPending();
-                       this.lookupRequest.always( OO.ui.bind( function () {
-                               this.popPending();
-                       }, this ) );
-               }
-       }
-       return deferred.promise();
-};
-
-/**
- * Get a new request object of the current lookup query value.
- *
- * @method
- * @abstract
- * @returns {jqXHR} jQuery AJAX object, or promise object with an .abort() method
- */
-OO.ui.LookupInputWidget.prototype.getLookupRequest = function () {
-       // Stub, implemented in subclass
-       return null;
-};
-
-/**
- * Handle successful lookup request.
- *
- * Overriding methods should call #populateLookupMenu when results are available and cache results
- * for future lookups in #lookupCache as an array of #OO.ui.MenuItemWidget objects.
- *
- * @method
- * @abstract
- * @param {Mixed} data Response from server
- */
-OO.ui.LookupInputWidget.prototype.onLookupRequestDone = function () {
-       // Stub, implemented in subclass
-};
-
-/**
- * Get a list of menu item widgets from the data stored by the lookup request's done handler.
- *
- * @method
- * @abstract
- * @param {Mixed} data Cached result data, usually an array
- * @returns {OO.ui.MenuItemWidget[]} Menu items
- */
-OO.ui.LookupInputWidget.prototype.getLookupMenuItemsFromData = function () {
-       // Stub, implemented in subclass
-       return [];
-};
-/**
- * Creates an OO.ui.OptionWidget object.
- *
- * @class
- * @abstract
- * @extends OO.ui.Widget
- * @mixins OO.ui.IconedElement
- * @mixins OO.ui.LabeledElement
- * @mixins OO.ui.IndicatedElement
- *
- * @constructor
- * @param {Mixed} data Option data
- * @param {Object} [config] Configuration options
- * @cfg {boolean} [selected=false] Select option
- * @cfg {boolean} [highlighted=false] Highlight option
- * @cfg {string} [rel] Value for `rel` attribute in DOM, allowing per-option styling
- */
-OO.ui.OptionWidget = function OoUiOptionWidget( data, config ) {
-       // Config intialization
-       config = config || {};
-
-       // Parent constructor
-       OO.ui.Widget.call( this, config );
-
-       // Mixin constructors
-       OO.ui.IconedElement.call( this, this.$( '<span>' ), config );
-       OO.ui.LabeledElement.call( this, this.$( '<span>' ), config );
-       OO.ui.IndicatedElement.call( this, this.$( '<span>' ), config );
-
-       // Properties
-       this.data = data;
-       this.selected = false;
-       this.highlighted = false;
-
-       // Initialization
-       this.$element
-               .data( 'oo-ui-optionWidget', this )
-               .attr( 'rel', config.rel )
-               .addClass( 'oo-ui-optionWidget' )
-               .append( this.$label );
-       this.setSelected( config.selected );
-       this.setHighlighted( config.highlighted );
-
-       // Options
-       this.$element
-               .prepend( this.$icon )
-               .append( this.$indicator );
-};
-
-/* Inheritance */
-
-OO.inheritClass( OO.ui.OptionWidget, OO.ui.Widget );
-
-OO.mixinClass( OO.ui.OptionWidget, OO.ui.IconedElement );
-OO.mixinClass( OO.ui.OptionWidget, OO.ui.LabeledElement );
-OO.mixinClass( OO.ui.OptionWidget, OO.ui.IndicatedElement );
-
-/* Static Properties */
-
-OO.ui.OptionWidget.static.tagName = 'li';
-
-OO.ui.OptionWidget.static.selectable = true;
-
-OO.ui.OptionWidget.static.highlightable = true;
-
-OO.ui.OptionWidget.static.scrollIntoViewOnSelect = false;
-
-/* Methods */
-
-/**
- * Check if option can be selected.
- *
- * @method
- * @returns {boolean} Item is selectable
- */
-OO.ui.OptionWidget.prototype.isSelectable = function () {
-       return this.constructor.static.selectable && !this.disabled;
-};
-
-/**
- * Check if option can be highlighted.
- *
- * @method
- * @returns {boolean} Item is highlightable
- */
-OO.ui.OptionWidget.prototype.isHighlightable = function () {
-       return this.constructor.static.highlightable && !this.disabled;
-};
-
-/**
- * Check if option is selected.
- *
- * @method
- * @returns {boolean} Item is selected
- */
-OO.ui.OptionWidget.prototype.isSelected = function () {
-       return this.selected;
-};
-
-/**
- * Check if option is highlighted.
- *
- * @method
- * @returns {boolean} Item is highlighted
- */
-OO.ui.OptionWidget.prototype.isHighlighted = function () {
-       return this.highlighted;
-};
-
-/**
- * Set selected state.
- *
- * @method
- * @param {boolean} [state=false] Select option
- * @chainable
- */
-OO.ui.OptionWidget.prototype.setSelected = function ( state ) {
-       if ( !this.disabled && this.constructor.static.selectable ) {
-               this.selected = !!state;
-               if ( this.selected ) {
-                       this.$element.addClass( 'oo-ui-optionWidget-selected' );
-                       if ( this.constructor.static.scrollIntoViewOnSelect ) {
-                               this.scrollElementIntoView();
-                       }
-               } else {
-                       this.$element.removeClass( 'oo-ui-optionWidget-selected' );
-               }
-       }
-       return this;
-};
-
-/**
- * Set highlighted state.
- *
- * @method
- * @param {boolean} [state=false] Highlight option
- * @chainable
- */
-OO.ui.OptionWidget.prototype.setHighlighted = function ( state ) {
-       if ( !this.disabled && this.constructor.static.highlightable ) {
-               this.highlighted = !!state;
-               if ( this.highlighted ) {
-                       this.$element.addClass( 'oo-ui-optionWidget-highlighted' );
-               } else {
-                       this.$element.removeClass( 'oo-ui-optionWidget-highlighted' );
-               }
-       }
-       return this;
-};
-
-/**
- * Make the option's highlight flash.
- *
- * @method
- * @param {Function} [done] Callback to execute when flash effect is complete.
- */
-OO.ui.OptionWidget.prototype.flash = function ( done ) {
-       var $this = this.$element;
-
-       if ( !this.disabled && this.constructor.static.highlightable ) {
-               $this.removeClass( 'oo-ui-optionWidget-highlighted' );
-               setTimeout( OO.ui.bind( function () {
-                       $this.addClass( 'oo-ui-optionWidget-highlighted' );
-                       if ( done ) {
-                               setTimeout( done, 100 );
-                       }
-               }, this ), 100 );
-       }
-};
-
-/**
- * Get option data.
- *
- * @method
- * @returns {Mixed} Option data
- */
-OO.ui.OptionWidget.prototype.getData = function () {
-       return this.data;
-};
-/**
- * Create an OO.ui.SelectWidget object.
- *
- * @class
- * @abstract
- * @extends OO.ui.Widget
- * @mixin OO.ui.GroupElement
- *
- * @constructor
- * @param {Object} [config] Configuration options
- */
-OO.ui.SelectWidget = function OoUiSelectWidget( config ) {
-       // Config intialization
-       config = config || {};
-
-       // Parent constructor
-       OO.ui.Widget.call( this, config );
-
-       // Mixin constructors
-       OO.ui.GroupElement.call( this, this.$element, config );
-
-       // Properties
-       this.pressed = false;
-       this.selecting = null;
-       this.hashes = {};
-
-       // Events
-       this.$element.on( {
-               'mousedown': OO.ui.bind( this.onMouseDown, this ),
-               'mouseup': OO.ui.bind( this.onMouseUp, this ),
-               'mousemove': OO.ui.bind( this.onMouseMove, this ),
-               'mouseover': OO.ui.bind( this.onMouseOver, this ),
-               'mouseleave': OO.ui.bind( this.onMouseLeave, this )
-       } );
-
-       // Initialization
-       this.$element.addClass( 'oo-ui-selectWidget' );
-};
-
-/* Inheritance */
-
-OO.inheritClass( OO.ui.SelectWidget, OO.ui.Widget );
-
-OO.mixinClass( OO.ui.SelectWidget, OO.ui.GroupElement );
-
-/* Events */
-
-/**
- * @event highlight
- * @param {OO.ui.OptionWidget|null} item Highlighted item
- */
-
-/**
- * @event select
- * @param {OO.ui.OptionWidget|null} item Selected item
- */
-
-/**
- * @event add
- * @param {OO.ui.OptionWidget[]} items Added items
- * @param {number} index Index items were added at
- */
-
-/**
- * @event remove
- * @param {OO.ui.OptionWidget[]} items Removed items
- */
-
-/* Static Properties */
-
-OO.ui.SelectWidget.static.tagName = 'ul';
-
-/* Methods */
-
-/**
- * Handle mouse down events.
- *
- * @method
- * @private
- * @param {jQuery.Event} e Mouse down event
- */
-OO.ui.SelectWidget.prototype.onMouseDown = function ( e ) {
-       var item;
-
-       if ( !this.disabled && e.which === 1 ) {
-               this.pressed = true;
-               item = this.getTargetItem( e );
-               if ( item && item.isSelectable() ) {
-                       this.intializeSelection( item );
-                       this.selecting = item;
-                       this.$( this.$.context ).one( 'mouseup', OO.ui.bind( this.onMouseUp, this ) );
-               }
-       }
-       return false;
-};
-
-/**
- * Handle mouse up events.
- *
- * @method
- * @private
- * @param {jQuery.Event} e Mouse up event
- */
-OO.ui.SelectWidget.prototype.onMouseUp = function ( e ) {
-       var item;
-       this.pressed = false;
-       if ( !this.selecting ) {
-               item = this.getTargetItem( e );
-               if ( item && item.isSelectable() ) {
-                       this.selecting = item;
-               }
-       }
-       if ( !this.disabled && e.which === 1 && this.selecting ) {
-               this.selectItem( this.selecting );
-               this.selecting = null;
-       }
-       return false;
-};
-
-/**
- * Handle mouse move events.
- *
- * @method
- * @private
- * @param {jQuery.Event} e Mouse move event
- */
-OO.ui.SelectWidget.prototype.onMouseMove = function ( e ) {
-       var item;
-
-       if ( !this.disabled && this.pressed ) {
-               item = this.getTargetItem( e );
-               if ( item && item !== this.selecting && item.isSelectable() ) {
-                       this.intializeSelection( item );
-                       this.selecting = item;
-               }
-       }
-       return false;
-};
-
-/**
- * Handle mouse over events.
- *
- * @method
- * @private
- * @param {jQuery.Event} e Mouse over event
- */
-OO.ui.SelectWidget.prototype.onMouseOver = function ( e ) {
-       var item;
-
-       if ( !this.disabled ) {
-               item = this.getTargetItem( e );
-               if ( item && item.isHighlightable() ) {
-                       this.highlightItem( item );
-               }
-       }
-       return false;
-};
-
-/**
- * Handle mouse leave events.
- *
- * @method
- * @private
- * @param {jQuery.Event} e Mouse over event
- */
-OO.ui.SelectWidget.prototype.onMouseLeave = function () {
-       if ( !this.disabled ) {
-               this.highlightItem();
-       }
-       return false;
-};
-
-/**
- * Get the closest item to a jQuery.Event.
- *
- * @method
- * @private
- * @param {jQuery.Event} e
- * @returns {OO.ui.OptionWidget|null} Outline item widget, `null` if none was found
- */
-OO.ui.SelectWidget.prototype.getTargetItem = function ( e ) {
-       var $item = this.$( e.target ).closest( '.oo-ui-optionWidget' );
-       if ( $item.length ) {
-               return $item.data( 'oo-ui-optionWidget' );
-       }
-       return null;
-};
-
-/**
- * Get selected item.
- *
- * @method
- * @returns {OO.ui.OptionWidget|null} Selected item, `null` if no item is selected
- */
-OO.ui.SelectWidget.prototype.getSelectedItem = function () {
-       var i, len;
-
-       for ( i = 0, len = this.items.length; i < len; i++ ) {
-               if ( this.items[i].isSelected() ) {
-                       return this.items[i];
-               }
-       }
-       return null;
-};
-
-/**
- * Get highlighted item.
- *
- * @method
- * @returns {OO.ui.OptionWidget|null} Highlighted item, `null` if no item is highlighted
- */
-OO.ui.SelectWidget.prototype.getHighlightedItem = function () {
-       var i, len;
-
-       for ( i = 0, len = this.items.length; i < len; i++ ) {
-               if ( this.items[i].isHighlighted() ) {
-                       return this.items[i];
-               }
-       }
-       return null;
-};
-
-/**
- * Get an existing item with equivilant data.
- *
- * @method
- * @param {Object} data Item data to search for
- * @returns {OO.ui.OptionWidget|null} Item with equivilent value, `null` if none exists
- */
-OO.ui.SelectWidget.prototype.getItemFromData = function ( data ) {
-       var hash = OO.getHash( data );
-
-       if ( hash in this.hashes ) {
-               return this.hashes[hash];
-       }
-
-       return null;
-};
-
-/**
- * Highlight an item.
- *
- * Highlighting is mutually exclusive.
- *
- * @method
- * @param {OO.ui.OptionWidget} [item] Item to highlight, omit to deselect all
- * @fires highlight
- * @chainable
- */
-OO.ui.SelectWidget.prototype.highlightItem = function ( item ) {
-       var i, len;
-
-       for ( i = 0, len = this.items.length; i < len; i++ ) {
-               this.items[i].setHighlighted( this.items[i] === item );
-       }
-       this.emit( 'highlight', item );
-
-       return this;
-};
-
-/**
- * Select an item.
- *
- * @method
- * @param {OO.ui.OptionWidget} [item] Item to select, omit to deselect all
- * @fires select
- * @chainable
- */
-OO.ui.SelectWidget.prototype.selectItem = function ( item ) {
-       var i, len;
-
-       for ( i = 0, len = this.items.length; i < len; i++ ) {
-               this.items[i].setSelected( this.items[i] === item );
-       }
-       this.emit( 'select', item );
-
-       return this;
-};
-
-/**
- * Setup selection and highlighting.
- *
- * This should be used to synchronize the UI with the model without emitting events that would in
- * turn update the model.
- *
- * @param {OO.ui.OptionWidget} [item] Item to select
- * @chainable
- */
-OO.ui.SelectWidget.prototype.intializeSelection = function( item ) {
-       var i, len, selected;
-
-       for ( i = 0, len = this.items.length; i < len; i++ ) {
-               selected = this.items[i] === item;
-               this.items[i].setSelected( selected );
-               this.items[i].setHighlighted( selected );
-       }
-
-       return this;
-};
-
-/**
- * Get an item relative to another one.
- *
- * @method
- * @param {OO.ui.OptionWidget} item Item to start at
- * @param {number} direction Direction to move in
- * @returns {OO.ui.OptionWidget|null} Item at position, `null` if there are no items in the menu
- */
-OO.ui.SelectWidget.prototype.getRelativeSelectableItem = function ( item, direction ) {
-       var inc = direction > 0 ? 1 : -1,
-               len = this.items.length,
-               index = item instanceof OO.ui.OptionWidget ?
-                       this.items.indexOf( item ) : ( inc > 0 ? -1 : 0 ),
-               stopAt = Math.max( Math.min( index, len - 1 ), 0 ),
-               i = inc > 0 ?
-                       // Default to 0 instead of -1, if nothing is selected let's start at the beginning
-                       Math.max( index, -1 ) :
-                       // Default to n-1 instead of -1, if nothing is selected let's start at the end
-                       Math.min( index, len );
-
-       while ( true ) {
-               i = ( i + inc + len ) % len;
-               item = this.items[i];
-               if ( item instanceof OO.ui.OptionWidget && item.isSelectable() ) {
-                       return item;
-               }
-               // Stop iterating when we've looped all the way around
-               if ( i === stopAt ) {
-                       break;
-               }
-       }
-       return null;
-};
-
-/**
- * Get the next selectable item.
- *
- * @method
- * @returns {OO.ui.OptionWidget|null} Item, `null` if ther aren't any selectable items
- */
-OO.ui.SelectWidget.prototype.getFirstSelectableItem = function () {
-       var i, len, item;
-
-       for ( i = 0, len = this.items.length; i < len; i++ ) {
-               item = this.items[i];
-               if ( item instanceof OO.ui.OptionWidget && item.isSelectable() ) {
-                       return item;
-               }
-       }
-
-       return null;
-};
-
-/**
- * Add items.
- *
- * When items are added with the same values as existing items, the existing items will be
- * automatically removed before the new items are added.
- *
- * @method
- * @param {OO.ui.OptionWidget[]} items Items to add
- * @param {number} [index] Index to insert items after
- * @fires add
- * @chainable
- */
-OO.ui.SelectWidget.prototype.addItems = function ( items, index ) {
-       var i, len, item, hash,
-               remove = [];
-
-       for ( i = 0, len = items.length; i < len; i++ ) {
-               item = items[i];
-               hash = OO.getHash( item.getData() );
-               if ( hash in this.hashes ) {
-                       // Remove item with same value
-                       remove.push( this.hashes[hash] );
-               }
-               this.hashes[hash] = item;
-       }
-       if ( remove.length ) {
-               this.removeItems( remove );
-       }
-
-       OO.ui.GroupElement.prototype.addItems.call( this, items, index );
-
-       // Always provide an index, even if it was omitted
-       this.emit( 'add', items, index === undefined ? this.items.length - items.length - 1 : index );
-
-       return this;
-};
-
-/**
- * Remove items.
- *
- * Items will be detached, not removed, so they can be used later.
- *
- * @method
- * @param {OO.ui.OptionWidget[]} items Items to remove
- * @fires remove
- * @chainable
- */
-OO.ui.SelectWidget.prototype.removeItems = function ( items ) {
-       var i, len, item, hash;
-
-       for ( i = 0, len = items.length; i < len; i++ ) {
-               item = items[i];
-               hash = OO.getHash( item.getData() );
-               if ( hash in this.hashes ) {
-                       // Remove existing item
-                       delete this.hashes[hash];
-               }
-               if ( item.isSelected() ) {
-                       this.selectItem( null );
-               }
-       }
-       OO.ui.GroupElement.prototype.removeItems.call( this, items );
-
-       this.emit( 'remove', items );
-
-       return this;
-};
-
-/**
- * Clear all items.
- *
- * Items will be detached, not removed, so they can be used later.
- *
- * @method
- * @fires remove
- * @chainable
- */
-OO.ui.SelectWidget.prototype.clearItems = function () {
-       var items = this.items.slice();
-
-       // Clear all items
-       this.hashes = {};
-       OO.ui.GroupElement.prototype.clearItems.call( this );
-       this.selectItem( null );
-
-       this.emit( 'remove', items );
-
-       return this;
-};
-/**
- * Creates an OO.ui.MenuItemWidget object.
- *
- * @class
- * @extends OO.ui.OptionWidget
- *
- * @constructor
- * @param {Mixed} data Item data
- * @param {Object} [config] Configuration options
- */
-OO.ui.MenuItemWidget = function OoUiMenuItemWidget( data, config ) {
-       // Configuration initialization
-       config = $.extend( { 'icon': 'check' }, config );
-
-       // Parent constructor
-       OO.ui.OptionWidget.call( this, data, config );
-
-       // Initialization
-       this.$element.addClass( 'oo-ui-menuItemWidget' );
-};
-
-/* Inheritance */
-
-OO.inheritClass( OO.ui.MenuItemWidget, OO.ui.OptionWidget );
-/**
- * Create an OO.ui.MenuWidget object.
- *
- * @class
- * @extends OO.ui.SelectWidget
- * @mixins OO.ui.ClippableElement
- *
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {OO.ui.InputWidget} [input] Input to bind keyboard handlers to
- */
-OO.ui.MenuWidget = function OoUiMenuWidget( config ) {
-       // Config intialization
-       config = config || {};
-
-       // Parent constructor
-       OO.ui.SelectWidget.call( this, config );
-
-       // Mixin constructors
-       OO.ui.ClippableElement.call( this, this.$group );
-
-       // Properties
-       this.newItems = [];
-       this.$input = config.input ? config.input.$input : null;
-       this.$previousFocus = null;
-       this.isolated = !config.input;
-       this.visible = false;
-       this.onKeyDownHandler = OO.ui.bind( this.onKeyDown, this );
-
-       // Initialization
-       this.$element.hide().addClass( 'oo-ui-menuWidget' );
-};
-
-/* Inheritance */
-
-OO.inheritClass( OO.ui.MenuWidget, OO.ui.SelectWidget );
-
-OO.mixinClass( OO.ui.MenuWidget, OO.ui.ClippableElement );
-
-/* Methods */
-
-/**
- * Handles key down events.
- *
- * @method
- * @param {jQuery.Event} e Key down event
- */
-OO.ui.MenuWidget.prototype.onKeyDown = function ( e ) {
-       var nextItem,
-               handled = false,
-               highlightItem = this.getHighlightedItem();
-
-       if ( !this.disabled && this.visible ) {
-               if ( !highlightItem ) {
-                       highlightItem = this.getSelectedItem();
-               }
-               switch ( e.keyCode ) {
-                       case OO.ui.Keys.ENTER:
-                               this.selectItem( highlightItem );
-                               handled = true;
-                               break;
-                       case OO.ui.Keys.UP:
-                               nextItem = this.getRelativeSelectableItem( highlightItem, -1 );
-                               handled = true;
-                               break;
-                       case OO.ui.Keys.DOWN:
-                               nextItem = this.getRelativeSelectableItem( highlightItem, 1 );
-                               handled = true;
-                               break;
-                       case OO.ui.Keys.ESCAPE:
-                               if ( highlightItem ) {
-                                       highlightItem.setHighlighted( false );
-                               }
-                               this.hide();
-                               handled = true;
-                               break;
-               }
-
-               if ( nextItem ) {
-                       this.highlightItem( nextItem );
-                       nextItem.scrollElementIntoView();
-               }
-
-               if ( handled ) {
-                       e.preventDefault();
-                       e.stopPropagation();
-                       return false;
-               }
-       }
-};
-
-/**
- * Check if the menu is visible.
- *
- * @method
- * @returns {boolean} Menu is visible
- */
-OO.ui.MenuWidget.prototype.isVisible = function () {
-       return this.visible;
-};
-
-/**
- * Bind key down listener
- *
- * @method
- */
-OO.ui.MenuWidget.prototype.bindKeyDownListener = function () {
-       if ( this.$input ) {
-               this.$input.on( 'keydown', this.onKeyDownHandler );
-       } else {
-               // Capture menu navigation keys
-               this.getElementWindow().addEventListener( 'keydown', this.onKeyDownHandler, true );
-       }
-};
-
-/**
- * Unbind key down listener
- *
- * @method
- */
-OO.ui.MenuWidget.prototype.unbindKeyDownListener = function () {
-       if ( this.$input ) {
-               this.$input.off( 'keydown' );
-       } else {
-               this.getElementWindow().removeEventListener( 'keydown', this.onKeyDownHandler, true );
-       }
-};
-
-/**
- * Select an item.
- *
- * The menu will stay open if an item is silently selected.
- *
- * @method
- * @param {OO.ui.OptionWidget} [item] Item to select, omit to deselect all
- * @chainable
- */
-OO.ui.MenuWidget.prototype.selectItem = function ( item ) {
-       // Parent method
-       OO.ui.SelectWidget.prototype.selectItem.call( this, item );
-
-       if ( !this.disabled ) {
-               if ( item ) {
-                       this.disabled = true;
-                       item.flash( OO.ui.bind( function () {
-                               this.hide();
-                               this.disabled = false;
-                       }, this ) );
-               } else {
-                       this.hide();
-               }
-       }
-
-       return this;
-};
-
-/**
- * Add items.
- *
- * Adding an existing item (by value) will move it.
- *
- * @method
- * @param {OO.ui.MenuItemWidget[]} items Items to add
- * @param {number} [index] Index to insert items after
- * @chainable
- */
-OO.ui.MenuWidget.prototype.addItems = function ( items, index ) {
-       var i, len, item;
-
-       // Parent method
-       OO.ui.SelectWidget.prototype.addItems.call( this, items, index );
-
-       for ( i = 0, len = items.length; i < len; i++ ) {
-               item = items[i];
-               if ( this.visible ) {
-                       // Defer fitting label until
-                       item.fitLabel();
-               } else {
-                       this.newItems.push( item );
-               }
-       }
-
-       return this;
-};
-
-/**
- * Show the menu.
- *
- * @method
- * @chainable
- */
-OO.ui.MenuWidget.prototype.show = function () {
-       var i, len;
-
-       if ( this.items.length ) {
-               this.$element.show();
-               this.visible = true;
-               this.bindKeyDownListener();
-
-               // Change focus to enable keyboard navigation
-               if ( this.isolated && this.$input && !this.$input.is( ':focus' ) ) {
-                       this.$previousFocus = this.$( ':focus' );
-                       this.$input.focus();
-               }
-               if ( this.newItems.length ) {
-                       for ( i = 0, len = this.newItems.length; i < len; i++ ) {
-                               this.newItems[i].fitLabel();
-                       }
-                       this.newItems = [];
-               }
-
-               this.setClipping( true );
-       }
-
-       return this;
-};
-
-/**
- * Hide the menu.
- *
- * @method
- * @chainable
- */
-OO.ui.MenuWidget.prototype.hide = function () {
-       this.$element.hide();
-       this.visible = false;
-       this.unbindKeyDownListener();
-
-       if ( this.isolated && this.$previousFocus ) {
-               this.$previousFocus.focus();
-               this.$previousFocus = null;
-       }
-
-       this.setClipping( false );
-
-       return this;
-};
-/**
- * Creates an OO.ui.MenuSectionItemWidget object.
- *
- * @class
- * @extends OO.ui.OptionWidget
- *
- * @constructor
- * @param {Mixed} data Item data
- * @param {Object} [config] Configuration options
- */
-OO.ui.MenuSectionItemWidget = function OoUiMenuSectionItemWidget( data, config ) {
-       // Parent constructor
-       OO.ui.OptionWidget.call( this, data, config );
-
-       // Initialization
-       this.$element.addClass( 'oo-ui-menuSectionItemWidget' );
-};
-
-/* Inheritance */
-
-OO.inheritClass( OO.ui.MenuSectionItemWidget, OO.ui.OptionWidget );
-
-OO.ui.MenuSectionItemWidget.static.selectable = false;
-
-OO.ui.MenuSectionItemWidget.static.highlightable = false;
-/**
- * Create an OO.ui.OutlineWidget object.
- *
- * @class
- * @extends OO.ui.SelectWidget
- *
- * @constructor
- * @param {Object} [config] Configuration options
- */
-OO.ui.OutlineWidget = function OoUiOutlineWidget( config ) {
-       // Config intialization
-       config = config || {};
-
-       // Parent constructor
-       OO.ui.SelectWidget.call( this, config );
-
-       // Initialization
-       this.$element.addClass( 'oo-ui-outlineWidget' );
-};
-
-/* Inheritance */
-
-OO.inheritClass( OO.ui.OutlineWidget, OO.ui.SelectWidget );
-/**
- * Creates an OO.ui.OutlineControlsWidget object.
- *
- * @class
- *
- * @constructor
- * @param {OO.ui.OutlineWidget} outline Outline to control
- * @param {Object} [config] Configuration options
- * @cfg {Object[]} [adders] List of icons to show as addable item types, each an object with
- *  name, title and icon properties
- */
-OO.ui.OutlineControlsWidget = function OoUiOutlineControlsWidget( outline, config ) {
-       // Configuration initialization
-       config = config || {};
-
-       // Parent constructor
-       OO.ui.Widget.call( this, config );
-
-       // Properties
-       this.outline = outline;
-       this.adders = {};
-       this.$adders = this.$( '<div>' );
-       this.$movers = this.$( '<div>' );
-       this.addButton = new OO.ui.ButtonWidget( {
-               '$': this.$,
-               'frameless': true,
-               'icon': 'add-item'
-       } );
-       this.upButton = new OO.ui.ButtonWidget( {
-               '$': this.$,
-               'frameless': true,
-               'icon': 'collapse',
-               'title': OO.ui.msg( 'ooui-outline-control-move-up' )
-       } );
-       this.downButton = new OO.ui.ButtonWidget( {
-               '$': this.$,
-               'frameless': true,
-               'icon': 'expand',
-               'title': OO.ui.msg( 'ooui-outline-control-move-down' )
-       } );
-
-       // Events
-       outline.connect( this, {
-               'select': 'onOutlineChange',
-               'add': 'onOutlineChange',
-               'remove': 'onOutlineChange'
-       } );
-       this.upButton.connect( this, { 'click': ['emit', 'move', -1] } );
-       this.downButton.connect( this, { 'click': ['emit', 'move', 1] } );
-
-       // Initialization
-       this.$element.addClass( 'oo-ui-outlineControlsWidget' );
-       this.$adders.addClass( 'oo-ui-outlineControlsWidget-adders' );
-       this.$movers
-               .addClass( 'oo-ui-outlineControlsWidget-movers' )
-               .append( this.upButton.$element, this.downButton.$element );
-       this.$element.append( this.$adders, this.$movers );
-       if ( config.adders && config.adders.length ) {
-               this.setupAdders( config.adders );
-       }
-};
-
-/* Inheritance */
-
-OO.inheritClass( OO.ui.OutlineControlsWidget, OO.ui.Widget );
-
-/* Events */
-
-/**
- * @event move
- * @param {number} places Number of places to move
- */
-
-/* Methods */
-
-/**
- * Handle outline change events.
- *
- * @method
- */
-OO.ui.OutlineControlsWidget.prototype.onOutlineChange = function () {
-       var i, len, firstMovable, lastMovable,
-               movable = false,
-               items = this.outline.getItems(),
-               selectedItem = this.outline.getSelectedItem();
-
-       if ( selectedItem && selectedItem.isMovable() ) {
-               movable = true;
-               i = -1;
-               len = items.length;
-               while ( ++i < len ) {
-                       if ( items[i].isMovable() ) {
-                               firstMovable = items[i];
-                               break;
-                       }
-               }
-               i = len;
-               while ( i-- ) {
-                       if ( items[i].isMovable() ) {
-                               lastMovable = items[i];
-                               break;
-                       }
-               }
-       }
-       this.upButton.setDisabled( !movable || selectedItem === firstMovable );
-       this.downButton.setDisabled( !movable || selectedItem === lastMovable );
-};
-
-/**
- * Setup adders icons.
- *
- * @method
- * @param {Object[]} adders List of configuations for adder buttons, each containing a name, title
- *  and icon property
- */
-OO.ui.OutlineControlsWidget.prototype.setupAdders = function ( adders ) {
-       var i, len, addition, button,
-               $buttons = this.$( [] );
-
-       this.$adders.append( this.addButton.$element );
-       for ( i = 0, len = adders.length; i < len; i++ ) {
-               addition = adders[i];
-               button = new OO.ui.ButtonWidget( {
-                       '$': this.$, 'frameless': true, 'icon': addition.icon, 'title': addition.title
-               } );
-               button.connect( this, { 'click': ['emit', 'add', addition.name] } );
-               this.adders[addition.name] = button;
-               this.$adders.append( button.$element );
-               $buttons = $buttons.add( button.$element );
-       }
-};
-/**
- * Creates an OO.ui.OutlineItemWidget object.
- *
- * @class
- * @extends OO.ui.OptionWidget
- *
- * @constructor
- * @param {Mixed} data Item data
- * @param {Object} [config] Configuration options
- * @cfg {number} [level] Indentation level
- * @cfg {boolean} [movable] Allow modification from outline controls
- */
-OO.ui.OutlineItemWidget = function OoUiOutlineItemWidget( data, config ) {
-       // Config intialization
-       config = config || {};
-
-       // Parent constructor
-       OO.ui.OptionWidget.call( this, data, config );
-
-       // Properties
-       this.level = 0;
-       this.movable = !!config.movable;
-
-       // Initialization
-       this.$element.addClass( 'oo-ui-outlineItemWidget' );
-       this.setLevel( config.level );
-};
-
-/* Inheritance */
-
-OO.inheritClass( OO.ui.OutlineItemWidget, OO.ui.OptionWidget );
-
-/* Static Properties */
-
-OO.ui.OutlineItemWidget.static.highlightable = false;
-
-OO.ui.OutlineItemWidget.static.scrollIntoViewOnSelect = true;
-
-OO.ui.OutlineItemWidget.static.levelClass = 'oo-ui-outlineItemWidget-level-';
-
-OO.ui.OutlineItemWidget.static.levels = 3;
-
-/* Methods */
-
-/**
- * Check if item is movable.
- *
- * Moveablilty is used by outline controls.
- *
- * @returns {boolean} Item is movable
- */
-OO.ui.OutlineItemWidget.prototype.isMovable = function () {
-       return this.movable;
-};
-
-/**
- * Get indentation level.
- *
- * @returns {number} Indentation level
- */
-OO.ui.OutlineItemWidget.prototype.getLevel = function () {
-       return this.level;
-};
-
-/**
- * Set indentation level.
- *
- * @method
- * @param {number} [level=0] Indentation level, in the range of [0,#maxLevel]
- * @chainable
- */
-OO.ui.OutlineItemWidget.prototype.setLevel = function ( level ) {
-       var levels = this.constructor.static.levels,
-               levelClass = this.constructor.static.levelClass,
-               i = levels;
-
-       this.level = level ? Math.max( 0, Math.min( levels - 1, level ) ) : 0;
-       while ( i-- ) {
-               if ( this.level === i ) {
-                       this.$element.addClass( levelClass + i );
-               } else {
-                       this.$element.removeClass( levelClass + i );
-               }
-       }
-
-       return this;
-};
-/**
- * Creates an OO.ui.BookletOutlineItemWidget object.
- *
- * @class
- * @extends OO.ui.OutlineItemWidget
- *
- * @constructor
- * @param {Mixed} data Item data
- * @param {Object} [config] Configuration options
- */
-OO.ui.BookletOutlineItemWidget = function OoUiBookletOutlineItemWidget( data, page, config ) {
-       // Configuration intialization
-       config = $.extend( {
-               'label': page.getLabel() || data,
-               'level': page.getLevel(),
-               'icon': page.getIcon(),
-               'indicator': page.getIndicator(),
-               'indicatorTitle': page.getIndicatorTitle(),
-               'movable': page.isMovable()
-       }, config );
-
-       // Parent constructor
-       OO.ui.OutlineItemWidget.call( this, data, config );
-
-       // Initialization
-       this.$element.addClass( 'oo-ui-bookletOutlineItemWidget' );
-};
-
-/* Inheritance */
-
-OO.inheritClass( OO.ui.BookletOutlineItemWidget, OO.ui.OutlineItemWidget );
-/**
- * Create an OO.ui.ButtonSelect object.
- *
- * @class
- * @extends OO.ui.OptionWidget
- * @mixins OO.ui.ButtonedElement
- * @mixins OO.ui.FlaggableElement
- *
- * @constructor
- * @param {Mixed} data Option data
- * @param {Object} [config] Configuration options
- */
-OO.ui.ButtonOptionWidget = function OoUiButtonOptionWidget( data, config ) {
-       // Parent constructor
-       OO.ui.OptionWidget.call( this, data, config );
-
-       // Mixin constructors
-       OO.ui.ButtonedElement.call( this, this.$( '<a>' ), config );
-       OO.ui.FlaggableElement.call( this, config );
-
-       // Initialization
-       this.$element.addClass( 'oo-ui-buttonOptionWidget' );
-       this.$button.append( this.$element.contents() );
-       this.$element.append( this.$button );
-};
-
-/* Inheritance */
-
-OO.inheritClass( OO.ui.ButtonOptionWidget, OO.ui.OptionWidget );
-
-OO.mixinClass( OO.ui.ButtonOptionWidget, OO.ui.ButtonedElement );
-OO.mixinClass( OO.ui.ButtonOptionWidget, OO.ui.FlaggableElement );
-
-/* Methods */
-
-/**
- * @inheritdoc
- */
-OO.ui.ButtonOptionWidget.prototype.setSelected = function ( state ) {
-       OO.ui.OptionWidget.prototype.setSelected.call( this, state );
-
-       this.setActive( state );
-
-       return this;
-};
-/**
- * Create an OO.ui.ButtonSelect object.
- *
- * @class
- * @extends OO.ui.SelectWidget
- *
- * @constructor
- * @param {Object} [config] Configuration options
- */
-OO.ui.ButtonSelectWidget = function OoUiButtonSelectWidget( config ) {
-       // Parent constructor
-       OO.ui.SelectWidget.call( this, config );
-
-       // Initialization
-       this.$element.addClass( 'oo-ui-buttonSelectWidget' );
-};
-
-/* Inheritance */
-
-OO.inheritClass( OO.ui.ButtonSelectWidget, OO.ui.SelectWidget );
-/**
- * Creates an OO.ui.PopupWidget object.
- *
- * @class
- * @extends OO.ui.Widget
- * @mixins OO.ui.LabeledElement
- *
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {boolean} [tail=true] Show tail pointing to origin of popup
- * @cfg {string} [align='center'] Alignment of popup to origin
- * @cfg {jQuery} [$container] Container to prevent popup from rendering outside of
- * @cfg {boolean} [autoClose=false] Popup auto-closes when it loses focus
- * @cfg {jQuery} [$autoCloseIgnore] Elements to not auto close when clicked
- * @cfg {boolean} [head] Show label and close button at the top
- */
-OO.ui.PopupWidget = function OoUiPopupWidget( config ) {
-       // Config intialization
-       config = config || {};
-
-       // Parent constructor
-       OO.ui.Widget.call( this, config );
-
-       // Mixin constructors
-       OO.ui.LabeledElement.call( this, this.$( '<div>' ), config );
-
-       // Properties
-       this.visible = false;
-       this.$popup = this.$( '<div>' );
-       this.$head = this.$( '<div>' );
-       this.$body = this.$( '<div>' );
-       this.$tail = this.$( '<div>' );
-       this.$container = config.$container || this.$( 'body' );
-       this.autoClose = !!config.autoClose;
-       this.$autoCloseIgnore = config.$autoCloseIgnore;
-       this.transitionTimeout = null;
-       this.tail = false;
-       this.align = config.align || 'center';
-       this.closeButton = new OO.ui.ButtonWidget( { '$': this.$, 'frameless': true, 'icon': 'close' } );
-       this.onMouseDownHandler = OO.ui.bind( this.onMouseDown, this );
-
-       // Events
-       this.closeButton.connect( this, { 'click': 'onCloseButtonClick' } );
-
-       // Initialization
-       this.useTail( config.tail !== undefined ? !!config.tail : true );
-       this.$body.addClass( 'oo-ui-popupWidget-body' );
-       this.$tail.addClass( 'oo-ui-popupWidget-tail' );
-       this.$head
-               .addClass( 'oo-ui-popupWidget-head' )
-               .append( this.$label, this.closeButton.$element );
-       if ( !config.head ) {
-               this.$head.hide();
-       }
-       this.$popup
-               .addClass( 'oo-ui-popupWidget-popup' )
-               .append( this.$head, this.$body );
-       this.$element.hide()
-               .addClass( 'oo-ui-popupWidget' )
-               .append( this.$popup, this.$tail );
-};
-
-/* Inheritance */
-
-OO.inheritClass( OO.ui.PopupWidget, OO.ui.Widget );
-
-OO.mixinClass( OO.ui.PopupWidget, OO.ui.LabeledElement );
-
-/* Events */
-
-/**
- * @event hide
- */
-
-/**
- * @event show
- */
-
-/* Methods */
-
-/**
- * Handles mouse down events.
- *
- * @method
- * @param {jQuery.Event} e Mouse down event
- */
-OO.ui.PopupWidget.prototype.onMouseDown = function ( e ) {
-       if (
-               this.visible &&
-               !$.contains( this.$element[0], e.target ) &&
-               ( !this.$autoCloseIgnore || !this.$autoCloseIgnore.has( e.target ).length )
-       ) {
-               this.hide();
-       }
-};
-
-/**
- * Bind mouse down listener
- *
- * @method
- */
-OO.ui.PopupWidget.prototype.bindMouseDownListener = function () {
-       // Capture clicks outside popup
-       this.getElementWindow().addEventListener( 'mousedown', this.onMouseDownHandler, true );
-};
-
-/**
- * Handles close button click events.
- *
- * @method
- */
-OO.ui.PopupWidget.prototype.onCloseButtonClick = function () {
-       if ( this.visible ) {
-               this.hide();
-       }
-};
-
-/**
- * Unbind mouse down listener
- *
- * @method
- */
-OO.ui.PopupWidget.prototype.unbindMouseDownListener = function () {
-       this.getElementWindow().removeEventListener( 'mousedown', this.onMouseDownHandler, true );
-};
-
-/**
- * Check if the popup is visible.
- *
- * @method
- * @returns {boolean} Popup is visible
- */
-OO.ui.PopupWidget.prototype.isVisible = function () {
-       return this.visible;
-};
-
-/**
- * Set whether to show a tail.
- *
- * @method
- * @returns {boolean} Make tail visible
- */
-OO.ui.PopupWidget.prototype.useTail = function ( value ) {
-       value = !!value;
-       if ( this.tail !== value ) {
-               this.tail = value;
-               if ( value ) {
-                       this.$element.addClass( 'oo-ui-popupWidget-tailed' );
-               } else {
-                       this.$element.removeClass( 'oo-ui-popupWidget-tailed' );
-               }
-       }
-};
-
-/**
- * Check if showing a tail.
- *
- * @method
- * @returns {boolean} tail is visible
- */
-OO.ui.PopupWidget.prototype.hasTail = function () {
-       return this.tail;
-};
-
-/**
- * Show the context.
- *
- * @method
- * @fires show
- * @chainable
- */
-OO.ui.PopupWidget.prototype.show = function () {
-       if ( !this.visible ) {
-               this.$element.show();
-               this.visible = true;
-               this.emit( 'show' );
-               if ( this.autoClose ) {
-                       this.bindMouseDownListener();
-               }
-       }
-       return this;
-};
-
-/**
- * Hide the context.
- *
- * @method
- * @fires hide
- * @chainable
- */
-OO.ui.PopupWidget.prototype.hide = function () {
-       if ( this.visible ) {
-               this.$element.hide();
-               this.visible = false;
-               this.emit( 'hide' );
-               if ( this.autoClose ) {
-                       this.unbindMouseDownListener();
-               }
-       }
-       return this;
-};
-
-/**
- * Updates the position and size.
- *
- * @method
- * @param {number} width Width
- * @param {number} height Height
- * @param {boolean} [transition=false] Use a smooth transition
- * @chainable
- */
-OO.ui.PopupWidget.prototype.display = function ( width, height, transition ) {
-       var padding = 10,
-               originOffset = Math.round( this.$element.offset().left ),
-               containerLeft = Math.round( this.$container.offset().left ),
-               containerWidth = this.$container.innerWidth(),
-               containerRight = containerLeft + containerWidth,
-               popupOffset = width * ( { 'left': 0, 'center': -0.5, 'right': -1 } )[this.align],
-               popupLeft = popupOffset - padding,
-               popupRight = popupOffset + padding + width + padding,
-               overlapLeft = ( originOffset + popupLeft ) - containerLeft,
-               overlapRight = containerRight - ( originOffset + popupRight );
-
-       // Prevent transition from being interrupted
-       clearTimeout( this.transitionTimeout );
-       if ( transition ) {
-               // Enable transition
-               this.$element.addClass( 'oo-ui-popupWidget-transitioning' );
-       }
-
-       if ( overlapRight < 0 ) {
-               popupOffset += overlapRight;
-       } else if ( overlapLeft < 0 ) {
-               popupOffset -= overlapLeft;
-       }
-
-       // Position body relative to anchor and resize
-       this.$popup.css( {
-               'left': popupOffset,
-               'width': width,
-               'height': height === undefined ? 'auto' : height
-       } );
-
-       if ( transition ) {
-               // Prevent transitioning after transition is complete
-               this.transitionTimeout = setTimeout( OO.ui.bind( function () {
-                       this.$element.removeClass( 'oo-ui-popupWidget-transitioning' );
-               }, this ), 200 );
-       } else {
-               // Prevent transitioning immediately
-               this.$element.removeClass( 'oo-ui-popupWidget-transitioning' );
-       }
-
-       return this;
-};
-/**
- * Button that shows and hides a popup.
- *
- * @class
- * @extends OO.ui.ButtonWidget
- * @mixins OO.ui.PopuppableElement
- *
- * @constructor
- * @param {Object} [config] Configuration options
- */
-OO.ui.PopupButtonWidget = function OoUiPopupButtonWidget( config ) {
-       // Parent constructor
-       OO.ui.ButtonWidget.call( this, config );
-
-       // Mixin constructors
-       OO.ui.PopuppableElement.call( this, config );
-
-       // Initialization
-       this.$element
-               .addClass( 'oo-ui-popupButtonWidget' )
-               .append( this.popup.$element );
-};
-
-/* Inheritance */
-
-OO.inheritClass( OO.ui.PopupButtonWidget, OO.ui.ButtonWidget );
-
-OO.mixinClass( OO.ui.PopupButtonWidget, OO.ui.PopuppableElement );
-
-/* Methods */
-
-/**
- * Handles mouse click events.
- *
- * @method
- * @param {jQuery.Event} e Mouse click event
- */
-OO.ui.PopupButtonWidget.prototype.onClick = function ( e ) {
-       // Skip clicks within the popup
-       if ( $.contains( this.popup.$element[0], e.target ) ) {
-               return;
-       }
-
-       if ( !this.disabled ) {
-               if ( this.popup.isVisible() ) {
-                       this.hidePopup();
-               } else {
-                       this.showPopup();
-               }
-               OO.ui.ButtonWidget.prototype.onClick.call( this );
-       }
-       return false;
-};
-/**
- * Creates an OO.ui.SearchWidget object.
- *
- * @class
- * @extends OO.ui.Widget
- *
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {string|jQuery} [placeholder] Placeholder text for query input
- * @cfg {string} [value] Initial query value
- */
-OO.ui.SearchWidget = function OoUiSearchWidget( config ) {
-       // Configuration intialization
-       config = config || {};
-
-       // Parent constructor
-       OO.ui.Widget.call( this, config );
-
-       // Properties
-       this.query = new OO.ui.TextInputWidget( {
-               '$': this.$,
-               'icon': 'search',
-               'placeholder': config.placeholder,
-               'value': config.value
-       } );
-       this.results = new OO.ui.SelectWidget( { '$': this.$ } );
-       this.$query = this.$( '<div>' );
-       this.$results = this.$( '<div>' );
-
-       // Events
-       this.query.connect( this, {
-               'change': 'onQueryChange',
-               'enter': 'onQueryEnter'
-       } );
-       this.results.connect( this, {
-               'highlight': 'onResultsHighlight',
-               'select': 'onResultsSelect'
-       } );
-       this.query.$input.on( 'keydown', OO.ui.bind( this.onQueryKeydown, this ) );
-
-       // Initialization
-       this.$query
-               .addClass( 'oo-ui-searchWidget-query' )
-               .append( this.query.$element );
-       this.$results
-               .addClass( 'oo-ui-searchWidget-results' )
-               .append( this.results.$element );
-       this.$element
-               .addClass( 'oo-ui-searchWidget' )
-               .append( this.$results, this.$query );
-};
-
-/* Inheritance */
-
-OO.inheritClass( OO.ui.SearchWidget, OO.ui.Widget );
-
-/* Events */
-
-/**
- * @event highlight
- * @param {Object|null} item Item data or null if no item is highlighted
- */
-
-/**
- * @event select
- * @param {Object|null} item Item data or null if no item is selected
- */
-
-/* Methods */
-
-/**
- * Handle query key down events.
- *
- * @method
- * @param {jQuery.Event} e Key down event
- */
-OO.ui.SearchWidget.prototype.onQueryKeydown = function ( e ) {
-       var highlightedItem, nextItem,
-               dir = e.which === OO.ui.Keys.DOWN ? 1 : ( e.which === OO.ui.Keys.UP ? -1 : 0 );
-
-       if ( dir ) {
-               highlightedItem = this.results.getHighlightedItem();
-               if ( !highlightedItem ) {
-                       highlightedItem = this.results.getSelectedItem();
-               }
-               nextItem = this.results.getRelativeSelectableItem( highlightedItem, dir );
-               this.results.highlightItem( nextItem );
-               nextItem.scrollElementIntoView();
-       }
-};
-
-/**
- * Handle select widget select events.
- *
- * Clears existing results. Subclasses should repopulate items according to new query.
- *
- * @method
- * @param {string} value New value
- */
-OO.ui.SearchWidget.prototype.onQueryChange = function () {
-       // Reset
-       this.results.clearItems();
-};
-
-/**
- * Handle select widget enter key events.
- *
- * Selects highlighted item.
- *
- * @method
- * @param {string} value New value
- */
-OO.ui.SearchWidget.prototype.onQueryEnter = function () {
-       // Reset
-       this.results.selectItem( this.results.getHighlightedItem() );
-};
-
-/**
- * Handle select widget highlight events.
- *
- * @method
- * @param {OO.ui.OptionWidget} item Highlighted item
- * @fires highlight
- */
-OO.ui.SearchWidget.prototype.onResultsHighlight = function ( item ) {
-       this.emit( 'highlight', item ? item.getData() : null );
-};
-
-/**
- * Handle select widget select events.
- *
- * @method
- * @param {OO.ui.OptionWidget} item Selected item
- * @fires select
- */
-OO.ui.SearchWidget.prototype.onResultsSelect = function ( item ) {
-       this.emit( 'select', item ? item.getData() : null );
-};
-
-/**
- * Get the query input.
- *
- * @method
- * @returns {OO.ui.TextInputWidget} Query input
- */
-OO.ui.SearchWidget.prototype.getQuery = function () {
-       return this.query;
-};
-
-/**
- * Get the results list.
- *
- * @method
- * @returns {OO.ui.SelectWidget} Select list
- */
-OO.ui.SearchWidget.prototype.getResults = function () {
-       return this.results;
-};
-/**
- * Creates an OO.ui.TextInputWidget object.
- *
- * @class
- * @extends OO.ui.InputWidget
- *
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {string} [placeholder] Placeholder text
- * @cfg {string} [icon] Symbolic name of icon
- * @cfg {boolean} [multiline=false] Allow multiple lines of text
- */
-OO.ui.TextInputWidget = function OoUiTextInputWidget( config ) {
-       config = config || {};
-
-       // Parent constructor
-       OO.ui.InputWidget.call( this, config );
-
-       // Properties
-       this.pending = 0;
-       this.multiline = !!config.multiline;
-
-       // Events
-       this.$input.on( 'keypress', OO.ui.bind( this.onKeyPress, this ) );
-
-       // Initialization
-       this.$element.addClass( 'oo-ui-textInputWidget' );
-       if ( config.icon ) {
-               this.$element.addClass( 'oo-ui-textInputWidget-decorated' );
-               this.$element.append(
-                       this.$( '<span>' )
-                               .addClass( 'oo-ui-textInputWidget-icon oo-ui-icon-' + config.icon )
-                               .mousedown( OO.ui.bind( function () {
-                                       this.$input.focus();
-                                       return false;
-                               }, this ) )
-               );
-       }
-       if ( config.placeholder ) {
-               this.$input.attr( 'placeholder', config.placeholder );
-       }
-};
-
-/* Inheritance */
-
-OO.inheritClass( OO.ui.TextInputWidget, OO.ui.InputWidget );
-
-/* Events */
-
-/**
- * User presses enter inside the text box.
- *
- * Not called if input is multiline.
- *
- * @event enter
- */
-
-/* Methods */
-
-/**
- * Handles key press events.
- *
- * @param {jQuery.Event} e Key press event
- * @fires enter If enter key is pressed and input is not multiline
- */
-OO.ui.TextInputWidget.prototype.onKeyPress = function ( e ) {
-       if ( e.which === OO.ui.Keys.ENTER && !this.multiline ) {
-               this.emit( 'enter' );
-       }
-};
-
-/**
- * Get input element.
- *
- * @method
- * @param {Object} [config] Configuration options
- * @returns {jQuery} Input element
- */
-OO.ui.TextInputWidget.prototype.getInputElement = function ( config ) {
-       return config.multiline ? this.$( '<textarea>' ) : this.$( '<input type="text" />' );
-};
-
-/* Methods */
-
-/**
- * Checks if input is pending.
- *
- * @method
- * @returns {boolean} Input is pending
- */
-OO.ui.TextInputWidget.prototype.isPending = function () {
-       return !!this.pending;
-};
-
-/**
- * Increases the pending stack.
- *
- * @method
- * @chainable
- */
-OO.ui.TextInputWidget.prototype.pushPending = function () {
-       this.pending++;
-       this.$element.addClass( 'oo-ui-textInputWidget-pending' );
-       this.$input.addClass( 'oo-ui-texture-pending' );
-       return this;
-};
-
-/**
- * Reduces the pending stack.
- *
- * Clamped at zero.
- *
- * @method
- * @chainable
- */
-OO.ui.TextInputWidget.prototype.popPending = function () {
-       this.pending = Math.max( 0, this.pending - 1 );
-       if ( !this.pending ) {
-               this.$element.removeClass( 'oo-ui-textInputWidget-pending' );
-               this.$input.removeClass( 'oo-ui-texture-pending' );
-       }
-       return this;
-};
-/**
- * Creates an OO.ui.TextInputMenuWidget object.
- *
- * @class
- * @extends OO.ui.MenuWidget
- *
- * @constructor
- * @param {OO.ui.TextInputWidget} input Text input widget to provide menu for
- * @param {Object} [config] Configuration options
- * @cfg {jQuery} [$container=input.$element] Element to render menu under
- */
-OO.ui.TextInputMenuWidget = function OoUiTextInputMenuWidget( input, config ) {
-       // Parent constructor
-       OO.ui.MenuWidget.call( this, config );
-
-       // Properties
-       this.input = input;
-       this.$container = config.$container || this.input.$element;
-       this.onWindowResizeHandler = OO.ui.bind( this.onWindowResize, this );
-
-       // Initialization
-       this.$element.addClass( 'oo-ui-textInputMenuWidget' );
-};
-
-/* Inheritance */
-
-OO.inheritClass( OO.ui.TextInputMenuWidget, OO.ui.MenuWidget );
-
-/* Methods */
-
-/**
- * Handle window resize event.
- *
- * @method
- * @param {jQuery.Event} e Window resize event
- */
-OO.ui.TextInputMenuWidget.prototype.onWindowResize = function () {
-       this.position();
-};
-
-/**
- * Shows the menu.
- *
- * @method
- * @chainable
- */
-OO.ui.TextInputMenuWidget.prototype.show = function () {
-       // Parent method
-       OO.ui.MenuWidget.prototype.show.call( this );
-
-       this.position();
-       this.$( this.getElementWindow() ).on( 'resize', this.onWindowResizeHandler );
-       return this;
-};
-
-/**
- * Hides the menu.
- *
- * @method
- * @chainable
- */
-OO.ui.TextInputMenuWidget.prototype.hide = function () {
-       // Parent method
-       OO.ui.MenuWidget.prototype.hide.call( this );
-
-       this.$( this.getElementWindow() ).off( 'resize', this.onWindowResizeHandler );
-       return this;
-};
-
-/**
- * Positions the menu.
- *
- * @method
- * @chainable
- */
-OO.ui.TextInputMenuWidget.prototype.position = function () {
-       var frameOffset,
-               $container = this.$container,
-               dimensions = $container.offset();
-
-       // Position under input
-       dimensions.top += $container.height();
-
-       // Compensate for frame position if in a differnt frame
-       if ( this.input.$.frame && this.input.$.context !== this.$element[0].ownerDocument ) {
-               frameOffset = OO.ui.Element.getRelativePosition(
-                       this.input.$.frame.$element, this.$element.offsetParent()
-               );
-               dimensions.left += frameOffset.left;
-               dimensions.top += frameOffset.top;
-       } else {
-               // Fix for RTL (for some reason, no need to fix if the frameoffset is set)
-               if ( this.$element.css( 'direction' ) === 'rtl' ) {
-                       dimensions.right = this.$element.parent().position().left -
-                               dimensions.width - dimensions.left;
-                       // Erase the value for 'left':
-                       delete dimensions.left;
-               }
-       }
-
-       this.$element.css( dimensions );
-       this.setIdealSize( $container.width() );
-       return this;
-};
-/**
- * Mixin for widgets with a boolean state.
- *
- * @class
- * @abstract
- *
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {boolean} [value=false] Initial value
- */
-OO.ui.ToggleWidget = function OoUiToggleWidget( config ) {
-       // Configuration initialization
-       config = config || {};
-
-       // Properties
-       this.value = null;
-
-       // Initialization
-       this.$element.addClass( 'oo-ui-toggleWidget' );
-       this.setValue( !!config.value );
-};
-
-/* Events */
-
-/**
- * @event change
- * @param {boolean} value Changed value
- */
-
-/* Methods */
-
-/**
- * Get the value of the toggle.
- *
- * @method
- * @returns {boolean} Toggle value
- */
-OO.ui.ToggleWidget.prototype.getValue = function () {
-       return this.value;
-};
-
-/**
- * Set the value of the toggle.
- *
- * @method
- * @param {boolean} value New value
- * @fires change
- * @chainable
- */
-OO.ui.ToggleWidget.prototype.setValue = function ( value ) {
-       value = !!value;
-       if ( this.value !== value ) {
-               this.value = value;
-               this.emit( 'change', value );
-               this.$element.toggleClass( 'oo-ui-toggleWidget-on', value );
-               this.$element.toggleClass( 'oo-ui-toggleWidget-off', !value );
-       }
-       return this;
-};
-/**
- * @class
- * @extends OO.ui.ButtonWidget
- * @mixins OO.ui.ToggleWidget
- *
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {boolean} [value=false] Initial value
- */
-OO.ui.ToggleButtonWidget = function OoUiToggleButtonWidget( config ) {
-       // Configuration initialization
-       config = config || {};
-
-       // Parent constructor
-       OO.ui.ButtonWidget.call( this, config );
-
-       // Mixin constructors
-       OO.ui.ToggleWidget.call( this, config );
-
-       // Initialization
-       this.$element.addClass( 'oo-ui-toggleButtonWidget' );
-};
-
-/* Inheritance */
-
-OO.inheritClass( OO.ui.ToggleButtonWidget, OO.ui.ButtonWidget );
-
-OO.mixinClass( OO.ui.ToggleButtonWidget, OO.ui.ToggleWidget );
-
-/* Methods */
-
-/**
- * @inheritdoc
- */
-OO.ui.ToggleButtonWidget.prototype.onClick = function () {
-       if ( !this.disabled ) {
-               this.setValue( !this.value );
-       }
-
-       // Parent method
-       return OO.ui.ButtonWidget.prototype.onClick.call( this );
-};
-
-/**
- * @inheritdoc
- */
-OO.ui.ToggleButtonWidget.prototype.setValue = function ( value ) {
-       value = !!value;
-       if ( value !== this.value ) {
-               this.setActive( value );
-       }
-
-       // Parent method
-       OO.ui.ToggleWidget.prototype.setValue.call( this, value );
-
-       return this;
-};
-/**
- * @class
- * @abstract
- * @extends OO.ui.Widget
- * @mixins OO.ui.ToggleWidget
- *
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {boolean} [value=false] Initial value
- */
-OO.ui.ToggleSwitchWidget = function OoUiToggleSwitchWidget( config ) {
-       // Parent constructor
-       OO.ui.Widget.call( this, config );
-
-       // Mixin constructors
-       OO.ui.ToggleWidget.call( this, config );
-
-       // Properties
-       this.dragging = false;
-       this.dragStart = null;
-       this.sliding = false;
-       this.$on = this.$( '<span>' );
-       this.$grip = this.$( '<span>' );
-
-       // Events
-       this.$element.on( 'click', OO.ui.bind( this.onClick, this ) );
-
-       // Initialization
-       this.$on.addClass( 'oo-ui-toggleSwitchWidget-on' );
-       this.$grip.addClass( 'oo-ui-toggleSwitchWidget-grip' );
-       this.$element
-               .addClass( 'oo-ui-toggleSwitchWidget' )
-               .append( this.$on, this.$grip );
-};
-
-/* Inheritance */
-
-OO.inheritClass( OO.ui.ToggleSwitchWidget, OO.ui.Widget );
-
-OO.mixinClass( OO.ui.ToggleSwitchWidget, OO.ui.ToggleWidget );
-
-/* Methods */
-
-/**
- * Handles mouse down events.
- *
- * @method
- * @param {jQuery.Event} e Mouse down event
- */
-OO.ui.ToggleSwitchWidget.prototype.onClick = function ( e ) {
-       if ( !this.disabled && e.which === 1 ) {
-               this.setValue( !this.value );
-       }
-};
-}() );
diff --git a/resources/oojs/oojs-ui.svg.css b/resources/oojs/oojs-ui.svg.css
deleted file mode 100644 (file)
index 185bcf0..0000000
+++ /dev/null
@@ -1,1880 +0,0 @@
-/*!
- * OOjs UI v0.1.0-pre-svg (a290673bbd)
- * https://www.mediawiki.org/wiki/OOjs_UI
- *
- * Copyright 2011–2014 OOjs Team and other contributors.
- * Released under the MIT license
- * http://oojs.mit-license.org
- *
- * Date: Wed Feb 12 2014 13:52:08 GMT-0800 (PST)
- */
-/*csslint vendor-prefix:false */
-
-/* Textures */
-
-.oo-ui-texture-pending {
-       /* @embed */
-       background-image: url(images/textures/pending.gif);
-}
-
-.oo-ui-texture-transparency {
-       /* @embed */
-       background-image: url(images/textures/transparency.png);
-}
-
-/* Animation */
-
-@-webkit-keyframes oo-ui-zoom-in {
-       from { -webkit-transform: scale(0.5); }
-       to { -webkit-transform: scale(1); }
-}
-
-@-moz-keyframes oo-ui-zoom-in {
-       from { -moz-transform: scale(0.5); }
-       to { -moz-transform: scale(1); }
-}
-
-@-o-keyframes oo-ui-zoom-in {
-       from { -o-transform: scale(0.5); }
-       to { -o-transform: scale(1); }
-}
-
-@keyframes oo-ui-zoom-in {
-       from { transform: scale(0.5); }
-       to { transform: scale(1); }
-}
-
-@-webkit-keyframes oo-ui-fade-in {
-       from { opacity: 0; }
-       to { opacity: 1; }
-}
-
-@-moz-keyframes oo-ui-fade-in {
-       from { opacity: 0; }
-       to { opacity: 1; }
-}
-
-@-o-keyframes oo-ui-fade-in {
-       from { opacity: 0; }
-       to { opacity: 1; }
-}
-
-@keyframes oo-ui-fade-in {
-       from { opacity: 0; }
-       to { opacity: 1; }
-}
-
-/* RTL Definitions */
-
-/* @noflip */
-.oo-ui-rtl {
-       direction: rtl;
-}
-/* @noflip */
-.oo-ui-ltr {
-       direction: ltr;
-}
-.oo-ui-dialog {
-       position: fixed;
-       top: 0;
-       right: 0;
-       bottom: 0;
-       left: 0;
-       padding: 1em;
-       line-height: 1em;
-       background-color: #fff;
-       background-color: rgba(255,255,255,0.5);
-       -webkit-animation: oo-ui-fade-in 250ms ease-in-out 0 1 normal;
-       -moz-animation: oo-ui-fade-in 250ms ease-in-out 0 1 normal;
-       -o-animation: oo-ui-fade-in 250ms ease-in-out 0 1 normal;
-       animation: oo-ui-fade-in 250ms ease-in-out 0 1 normal;
-}
-
-.oo-ui-dialog-closing {
-       -webkit-animation: oo-ui-fade-in 250ms ease-in-out 0 1 reverse;
-       -moz-animation: oo-ui-fade-in 250ms ease-in-out 0 1 reverse;
-       -o-animation: oo-ui-fade-in 250ms ease-in-out 0 1 reverse;
-       animation: oo-ui-fade-in 250ms ease-in-out 0 1 reverse;
-}
-
-.oo-ui-dialog .oo-ui-window-frame {
-       position: fixed;
-       top: 1em;
-       right: 0;
-       bottom: 1em;
-       left: 0;
-       margin: auto;
-       width: 800px;
-       min-height: 12em;
-       max-height: 600px;
-       background-color: #fff;
-       border: solid 1px #ccc;
-       border-radius: 0.5em;
-       box-shadow: 0 0.2em 1em rgba(0, 0, 0, 0.3);
-       overflow: hidden;
-       -webkit-animation: oo-ui-zoom-in 250ms ease-in-out 0 1 normal;
-       -moz-animation: oo-ui-zoom-in 250ms ease-in-out 0 1 normal;
-       -o-animation: oo-ui-zoom-in 250ms ease-in-out 0 1 normal;
-       animation: oo-ui-zoom-in 250ms ease-in-out 0 1 normal;
-}
-
-.oo-ui-dialog .oo-ui-window-frame.oo-ui-window-frame-small {
-       max-width: 600px;
-       max-height: 400px;
-}
-
-.oo-ui-dialog-closing .oo-ui-window-frame {
-       -webkit-animation: oo-ui-zoom-in 250ms ease-in-out 0 1 reverse;
-       -moz-animation: oo-ui-zoom-in 250ms ease-in-out 0 1 reverse;
-       -o-animation: oo-ui-zoom-in 250ms ease-in-out 0 1 reverse;
-       animation: oo-ui-zoom-in 250ms ease-in-out 0 1 reverse;
-}
-
-.oo-ui-dialog .oo-ui-frame {
-       width: 100%;
-       height: 100%;
-}
-
-.oo-ui-dialog-content .oo-ui-window-head,
-.oo-ui-dialog-content .oo-ui-window-body,
-.oo-ui-dialog-content .oo-ui-window-foot {
-       position: absolute;
-       left: 0;
-       right: 0;
-       -webkit-box-sizing: border-box;
-       -moz-box-sizing: border-box;
-       box-sizing: border-box;
-       overflow: hidden;
-}
-
-.oo-ui-dialog-content .oo-ui-window-head {
-       top: 0;
-       height: 3.8em;
-       padding: 0.5em;
-}
-
-.oo-ui-dialog-content .oo-ui-window-foot {
-       bottom: 0;
-       height: 4.8em;
-       padding: 1em;
-}
-
-.oo-ui-dialog-content .oo-ui-window-body {
-       box-shadow: 0 0 0.66em rgba(0,0,0,0.25);
-       top: 3.8em;
-       bottom: 4.8em;
-}
-
-.oo-ui-dialog-content-footless .oo-ui-window-body {
-       bottom: 0;
-}
-
-.oo-ui-dialog-content-footless .oo-ui-window-foot {
-       display: none;
-}
-
-.oo-ui-dialog-content .oo-ui-window-icon {
-       width: 2.4em;
-       height: 2.8em;
-       line-height: 2.8em;
-}
-
-.oo-ui-dialog-content .oo-ui-window-title {
-       line-height: 2.8em;
-}
-
-.oo-ui-dialog-content .oo-ui-window-foot .oo-ui-buttonedElement-framed {
-       float: left;
-       margin: 0.125em 0.25em;
-}
-
-.oo-ui-dialog-content .oo-ui-window-foot .oo-ui-buttonedElement-framed.oo-ui-flaggableElement-primary,
-.oo-ui-dialog-content .oo-ui-window-foot .oo-ui-buttonedElement-framed.oo-ui-flaggableElement-constructive,
-.oo-ui-dialog-content .oo-ui-window-foot .oo-ui-buttonedElement-framed.oo-ui-flaggableElement-destructive {
-       float: right;
-}
-
-.oo-ui-dialog-content .oo-ui-window-closeButton {
-       float: right;
-       margin: 0.25em 0.25em;
-}
-
-/* OO.ui.ButtonedElement */
-
-a.oo-ui-buttonedElement-button {
-       color: #333;
-       cursor: pointer;
-       display: inline-block;
-       vertical-align: middle;
-       -webkit-touch-callout: none;
-       -webkit-user-select: none;
-       -moz-user-select: none;
-       -ms-user-select: none;
-       user-select: none;
-}
-
-.oo-ui-buttonedElement .oo-ui-buttonedElement-button > .oo-ui-indicatedElement-indicator,
-.oo-ui-buttonedElement .oo-ui-buttonedElement-button > .oo-ui-iconedElement-icon {
-       display: none;
-}
-
-.oo-ui-buttonedElement.oo-ui-indicatedElement .oo-ui-buttonedElement-button > .oo-ui-indicatedElement-indicator,
-.oo-ui-buttonedElement.oo-ui-iconedElement .oo-ui-buttonedElement-button > .oo-ui-iconedElement-icon {
-       opacity: 0.8;
-       display: inline-block;
-       vertical-align: middle;
-       background-position: center center;
-       background-repeat: no-repeat;
-       width: 1.9em;
-       height: 1.9em;
-}
-
-.oo-ui-buttonedElement .oo-ui-buttonedElement-button > .oo-ui-iconedElement-icon {
-       margin-left: 0;
-}
-
-.oo-ui-buttonedElement .oo-ui-buttonedElement-button > .oo-ui-indicatedElement-indicator {
-       margin-right: -0.75em;
-}
-
-.oo-ui-buttonedElement-frameless {
-       display: inline-block;
-       position: relative;
-       -webkit-transition: opacity 200ms;
-       -moz-transition: opacity 200ms;
-       -o-transition: opacity 200ms;
-       transition: opacity 200ms;
-}
-
-.oo-ui-buttonedElement-frameless .oo-ui-buttonedElement-button:hover > .oo-ui-iconedElement-icon,
-.oo-ui-buttonedElement-frameless .oo-ui-buttonedElement-button:focus > .oo-ui-iconedElement-icon {
-       opacity: 1;
-}
-
-.oo-ui-buttonedElement-frameless.oo-ui-widget-disabled .oo-ui-buttonedElement-button > .oo-ui-iconedElement-icon {
-       opacity: 0.2;
-}
-
-.oo-ui-buttonedElement-frameless .oo-ui-buttonedElement-button > .oo-ui-labeledElement-label {
-       display: inline-block;
-       vertical-align: middle;
-       margin-left: 0.25em;
-       color: #333;
-}
-
-.oo-ui-buttonedElement-frameless .oo-ui-buttonedElement-button:hover > .oo-ui-labeledElement-label,
-.oo-ui-buttonedElement-frameless .oo-ui-buttonedElement-button:focus > .oo-ui-labeledElement-label {
-       color: #000;
-}
-
-.oo-ui-buttonedElement-frameless.oo-ui-widget-disabled .oo-ui-buttonedElement-button > .oo-ui-labeledElement-label {
-       color: #ccc;
-}
-
-/* OO.ui.ButtonWidget */
-
-.oo-ui-buttonedElement-framed .oo-ui-buttonedElement-button {
-       display: inline-block;
-       font-size: 1em;
-       margin: 0.1em 0;
-       padding: 0.2em 0.8em;
-       border-radius: 0.3em;
-       vertical-align: top;
-       text-shadow: 0 1px 1px rgba(255, 255, 255, 0.5);
-       box-shadow: 0 0.1em 0.25em rgba(0, 0, 0, 0.1);
-       text-align: center;
-
-       /* Animation */
-       -webkit-transition: border-color 100ms;
-       -moz-transition: border-color 100ms;
-       -o-transition: border-color 100ms;
-       transition: border-color 100ms;
-
-       /* Gray */
-       border: 1px #c9c9c9 solid;
-       background-color: #dddddd;
-       filter: progid:DXImageTransform.Microsoft.gradient(
-               GradientType=0,startColorstr=#ffffff, endColorstr=#dddddd
-       );
-       background-image: -webkit-gradient(
-               linear, right top, right bottom, color-stop(0%,#ffffff), color-stop(100%,#dddddd)
-       );
-       background-image: -webkit-linear-gradient(top, #ffffff 0%, #dddddd 100%);
-       background-image: -moz-linear-gradient(top, #ffffff 0%, #dddddd 100%);
-       background-image: -ms-linear-gradient(top, #ffffff 0%, #dddddd 100%);
-       background-image: -o-linear-gradient(top, #ffffff 0%, #dddddd 100%);
-       background-image: linear-gradient(top, #ffffff 0%, #dddddd 100%);
-}
-
-.oo-ui-buttonedElement-framed .oo-ui-buttonedElement-button:hover,
-.oo-ui-buttonedElement-framed .oo-ui-buttonedElement-button:focus {
-       border-color: #aaa;
-}
-
-.oo-ui-buttonedElement-framed .oo-ui-buttonedElement-button:active,
-.oo-ui-buttonedElement-framed.oo-ui-buttonedElement-active .oo-ui-buttonedElement-button {
-       box-shadow: inset 0 1px 4px 0 rgba(0, 0, 0, 0.07);
-       color: black;
-
-       /* Gray */
-       border-color: #c9c9c9;
-       background-color: #dddddd;
-       filter: progid:DXImageTransform.Microsoft.gradient(
-               GradientType=0,startColorstr=#dddddd, endColorstr=#ffffff
-       );
-       background-image: -webkit-gradient(
-               linear, right top, right bottom, color-stop(0%,#dddddd), color-stop(100%,#ffffff)
-       );
-       background-image: -webkit-linear-gradient(top, #dddddd 0%, #ffffff 100%);
-       background-image: -moz-linear-gradient(top, #dddddd 0%, #ffffff 100%);
-       background-image: -ms-linear-gradient(top, #dddddd 0%, #ffffff 100%);
-       background-image: -o-linear-gradient(top, #dddddd 0%, #ffffff 100%);
-       background-image: linear-gradient(top, #dddddd 0%, #ffffff 100%);
-}
-
-.oo-ui-buttonedElement-framed.oo-ui-iconedElement .oo-ui-buttonedElement-button > .oo-ui-iconedElement-icon {
-       margin-left: -0.5em;
-       margin-right: -0.5em;
-}
-
-.oo-ui-buttonedElement-framed.oo-ui-iconedElement.oo-ui-labeledElement .oo-ui-buttonedElement-button > .oo-ui-iconedElement-icon {
-       margin-left: -0.5em;
-       margin-right: 0;
-}
-
-.oo-ui-buttonedElement-framed .oo-ui-buttonedElement-button > .oo-ui-labeledElement-label {
-       display: inline-block;
-       vertical-align: middle;
-       line-height: 1.9em;
-}
-
-.oo-ui-buttonedElement-framed.oo-ui-flaggableElement-destructive .oo-ui-buttonedElement-button {
-       /* Red text */
-       color: #d45353;
-}
-
-.oo-ui-buttonedElement-framed.oo-ui-flaggableElement-constructive .oo-ui-buttonedElement-button {
-       /* Green */
-       border: solid 1px #b8d892;
-       background-color: #f0fbe1;
-       filter: progid:DXImageTransform.Microsoft.gradient(
-               GradientType=0,startColorstr=#f0fbe1, endColorstr=#c3e59a
-       );
-       background-image: -webkit-gradient(
-               linear, right top, right bottom, color-stop(0%,#f0fbe1), color-stop(100%,#c3e59a)
-       );
-       background-image: -webkit-linear-gradient(top, #f0fbe1 0%, #c3e59a 100%);
-       background-image: -moz-linear-gradient(top, #f0fbe1 0%, #c3e59a 100%);
-       background-image: -ms-linear-gradient(top, #f0fbe1 0%, #c3e59a 100%);
-       background-image: -o-linear-gradient(top, #f0fbe1 0%, #c3e59a 100%);
-       background-image: linear-gradient(top, #f0fbe1 0%, #c3e59a 100%);
-}
-
-.oo-ui-buttonedElement-framed.oo-ui-flaggableElement-constructive .oo-ui-buttonedElement-button:hover,
-.oo-ui-buttonedElement-framed.oo-ui-flaggableElement-constructive .oo-ui-buttonedElement-button:focus {
-       border-color: #adcb89;
-}
-
-.oo-ui-buttonedElement-framed.oo-ui-flaggableElement-constructive .oo-ui-buttonedElement-button:active,
-.oo-ui-buttonedElement-framed.oo-ui-buttonedElement-active.oo-ui-flaggableElement-constructive .oo-ui-buttonedElement-button {
-       /* Green */
-       border: solid 1px #b8d892;
-       background-color: #c3e59a;
-       filter: progid:DXImageTransform.Microsoft.gradient(
-               GradientType=0,startColorstr=#c3e59a, endColorstr=#f0fbe1
-       );
-       background-image: -webkit-gradient(
-               linear, right top, right bottom, color-stop(0%,#c3e59a), color-stop(100%,#f0fbe1)
-       );
-       background-image: -webkit-linear-gradient(top, #c3e59a 0%, #f0fbe1 100%);
-       background-image: -moz-linear-gradient(top, #c3e59a 0%, #f0fbe1 100%);
-       background-image: -ms-linear-gradient(top, #c3e59a 0%, #f0fbe1 100%);
-       background-image: -o-linear-gradient(top, #c3e59a 0%, #f0fbe1 100%);
-       background-image: linear-gradient(top, #c3e59a 0%, #f0fbe1 100%);
-}
-
-.oo-ui-buttonedElement-framed.oo-ui-flaggableElement-primary .oo-ui-buttonedElement-button {
-       /* Blue */
-       border: solid 1px #a6cee1;
-       background-color: #eaf4fa;
-       filter: progid:DXImageTransform.Microsoft.gradient(
-               GradientType=0,startColorstr=#eaf4fa, endColorstr=#b0d9ee
-       );
-       background-image: -webkit-gradient(
-               linear, right top, right bottom, color-stop(0%,#eaf4fa), color-stop(100%,#b0d9ee)
-       );
-       background-image: -webkit-linear-gradient(top, #eaf4fa 0%, #b0d9ee 100%);
-       background-image: -moz-linear-gradient(top, #eaf4fa 0%, #b0d9ee 100%);
-       background-image: -ms-linear-gradient(top, #eaf4fa 0%, #b0d9ee 100%);
-       background-image: -o-linear-gradient(top, #eaf4fa 0%, #b0d9ee 100%);
-       background-image: linear-gradient(top, #eaf4fa 0%, #b0d9ee 100%);
-}
-
-.oo-ui-buttonedElement-framed.oo-ui-flaggableElement-primary .oo-ui-buttonedElement-button:hover,
-.oo-ui-buttonedElement-framed.oo-ui-flaggableElement-primary .oo-ui-buttonedElement-button:focus {
-       border-color: #9dc2d4;
-}
-
-.oo-ui-buttonedElement-framed.oo-ui-flaggableElement-primary .oo-ui-buttonedElement-button:active,
-.oo-ui-buttonedElement-framed.oo-ui-buttonedElement-active.oo-ui-flaggableElement-primary .oo-ui-buttonedElement-button {
-       /* Blue */
-       border: solid 1px #a6cee1;
-       background-color: #b0d9ee;
-       filter: progid:DXImageTransform.Microsoft.gradient(
-               GradientType=0,startColorstr=#b0d9ee, endColorstr=#eaf4fa
-       );
-       background-image: -webkit-gradient(
-               linear, right top, right bottom, color-stop(0%,#b0d9ee), color-stop(100%,#eaf4fa)
-       );
-       background-image: -webkit-linear-gradient(top, #b0d9ee 0%, #eaf4fa 100%);
-       background-image: -moz-linear-gradient(top, #b0d9ee 0%, #eaf4fa 100%);
-       background-image: -ms-linear-gradient(top, #b0d9ee 0%, #eaf4fa 100%);
-       background-image: -o-linear-gradient(top, #b0d9ee 0%, #eaf4fa 100%);
-       background-image: linear-gradient(top, #b0d9ee 0%, #eaf4fa 100%);
-}
-
-.oo-ui-buttonedElement-framed.oo-ui-widget-disabled .oo-ui-buttonedElement-button,
-.oo-ui-buttonedElement-framed.oo-ui-widget-disabled .oo-ui-buttonedElement-button:active,
-.oo-ui-buttonedElement-framed.oo-ui-buttonedElement-active.oo-ui-widget-disabled .oo-ui-buttonedElement-button:active {
-       opacity: 0.5;
-       cursor: default;
-       box-shadow: none;
-       color: #333;
-       background: #eee;
-}
-
-.oo-ui-buttonedElement-framed.oo-ui-widget-disabled .oo-ui-buttonedElement-button:hover,
-.oo-ui-buttonedElement-framed.oo-ui-widget-disabled .oo-ui-buttonedElement-button:focus {
-       border-color: #ccc;
-       box-shadow: none;
-}
-
-/* OO.ui.LabeledElement */
-
-.oo-ui-labeledElement-label {
-       display: block;
-}
-
-.oo-ui-clippableElement-clippable {
-       -webkit-box-sizing: border-box;
-       -moz-box-sizing: border-box;
-       box-sizing: border-box;
-}
-.oo-ui-frame {
-       margin: 0;
-       padding: 0;
-}
-
-.oo-ui-frame-body {
-       margin: 0;
-       padding: 0;
-       background: none;
-}
-
-.oo-ui-frame-content {
-       font-family: sans-serif;
-       font-size: 0.8em;
-}
-/* OO.ui.GridLayout */
-/* OO.ui.PanelLayout */
-
-.oo-ui-gridLayout,
-.oo-ui-panelLayout {
-       position: absolute;
-       top: 0;
-       left: 0;
-       right: 0;
-       bottom: 0;
-}
-
-.oo-ui-panelLayout-scrollable {
-       overflow-y: auto;
-}
-
-.oo-ui-panelLayout-padded {
-       padding: 2em;
-}
-
-/* OO.ui.FieldsetLayout */
-
-.oo-ui-fieldsetLayout {
-       border: none;
-       margin: 0;
-       padding: 0;
-}
-
-.oo-ui-fieldsetLayout + .oo-ui-fieldsetLayout {
-       margin-top: 2em;
-}
-
-.oo-ui-fieldsetLayout-labeled {
-       margin-top: -0.75em;
-}
-
-.oo-ui-fieldsetLayout > legend.oo-ui-labeledElement-label {
-       font-size: 1.5em;
-       margin-bottom: 0.5em;
-}
-
-.oo-ui-fieldsetLayout-decorated > legend.oo-ui-labeledElement-label {
-       padding-left: 1.75em;
-       background-position: left center;
-       background-repeat: no-repeat;
-}
-
-/* OO.ui.BookletLayout */
-
-.oo-ui-bookletLayout-stackLayout .oo-ui-panelLayout {
-       padding: 1.5em;
-       width: 100%;
-       -webkit-box-sizing: border-box;
-       -moz-box-sizing: border-box;
-       box-sizing: border-box;
-}
-
-.oo-ui-bookletLayout-stackLayout .oo-ui-panelLayout-scrollable {
-       overflow-y: auto;
-}
-
-.oo-ui-bookletLayout-stackLayout .oo-ui-panelLayout-padded {
-       padding: 2em;
-}
-
-.oo-ui-bookletLayout-outlinePanel {
-       border-right: solid 1px #ddd;
-}
-
-.oo-ui-bookletLayout-outlinePanel-editable .oo-ui-outlineWidget {
-       position: absolute;
-       top: 0;
-       left: 0;
-       right: 0;
-       bottom: 3em;
-       overflow-y: auto;
-}
-
-.oo-ui-bookletLayout-outlinePanel .oo-ui-outlineControlsWidget {
-       position: absolute;
-       bottom: 0;
-       left: 0;
-       right: 0;
-       box-shadow: 0 0 0.25em rgba(0,0,0,0.25);
-}
-
-.oo-ui-stackLayout > .oo-ui-panelLayout {
-       display: none;
-}
-
-.oo-ui-stackLayout-continuous > .oo-ui-panelLayout {
-       display: block;
-       position: relative;
-       margin-bottom: 1em;
-       box-shadow: 0 0 0.5em rgba(0,0,0,0.25);
-}
-
-.oo-ui-stackLayout-continuous > .oo-ui-panelLayout:last-child {
-       margin-bottom: 0;
-}
-/* OO.ui.PopupTool */
-
-.oo-ui-popupTool .oo-ui-popupWidget {
-       margin-left: 1.25em;
-       font-size: 0.8em;
-}
-
-.oo-ui-popupTool .oo-ui-popupWidget-popup,
-.oo-ui-popupTool .oo-ui-popupWidget-tail {
-       z-index: 4;
-}
-.oo-ui-toolbar {
-       clear: both;
-}
-
-.oo-ui-toolbar-bar {
-       border-bottom: solid 1px #ccc;
-       background-color: white;
-       /* @embed */
-       background-image: url(images/fade-up.png);
-       background-position: left bottom;
-       background-repeat: repeat-x;
-       padding-bottom: 1px;
-       line-height: 1em;
-}
-
-.oo-ui-toolbar-bar .oo-ui-toolbar-bar {
-       border: none;
-       background: none;
-}
-
-.oo-ui-toolbar-bottom .oo-ui-toolbar-bar {
-       position: absolute;
-}
-
-.oo-ui-toolbar-actions {
-       float: right;
-}
-
-.oo-ui-toolbar-tools {
-       float: left;
-}
-
-.oo-ui-toolbar-tools,
-.oo-ui-toolbar-actions,
-.oo-ui-toolbar-shadow {
-       -webkit-user-select: none;
-       -moz-user-select: none;
-       -ms-user-select: none;
-       -o-user-select: none;
-       user-select: none;
-}
-
-.oo-ui-toolbar-actions .oo-ui-popupWidget {
-       -webkit-touch-callout: default;
-       -webkit-user-select: all;
-       -moz-user-select: all;
-       -ms-user-select: all;
-       user-select: all;
-}
-
-.oo-ui-toolbar-shadow {
-       /* @embed */
-       background-image: url(images/toolbar-shadow.png);
-       background-position: left top;
-       background-repeat: repeat-x;
-       position: absolute;
-       bottom: -9px;
-       height: 9px;
-       width: 100%;
-       pointer-events: none;
-       -webkit-transition: opacity 500ms ease-in-out;
-       -moz-transition: opacity 500ms ease-in-out;
-       -o-transition: opacity 500ms ease-in-out;
-       transition: opacity 500ms ease-in-out;
-       opacity: 0.125;
-}
-/* OO.ui.ToolGroup */
-
-.oo-ui-toolGroup {
-       display: inline-block;
-       margin: 0.3em;
-       vertical-align: middle;
-       border-radius: 0.25em;
-       border: solid 1px transparent;
-       -webkit-transition: border-color 300ms;
-       -moz-transition: border-color 300ms;
-       -o-transition: border-color 300ms;
-       transition: border-color 300ms;
-}
-
-.oo-ui-toolGroup:hover {
-       border-color: rgba(0,0,0,0.1);
-}
-
-.oo-ui-toolGroup-empty {
-       display: none;
-}
-
-.oo-ui-toolGroup .oo-ui-tool-link .oo-ui-tool-title {
-       color: #000;
-}
-
-.oo-ui-toolGroup .oo-ui-tool-link .oo-ui-iconedElement-icon {
-       background-position: center center;
-       background-repeat: no-repeat;
-}
-
-/* OO.ui.BarToolGroup */
-
-.oo-ui-barToolGroup > .oo-ui-iconedElement-icon,
-.oo-ui-barToolGroup > .oo-ui-iconedElement-label {
-       display: none;
-}
-
-.oo-ui-barToolGroup .oo-ui-tool {
-       display: inline-block;
-       position: relative;
-       vertical-align: top;
-       margin: -1px 0 -1px -1px;
-       border: solid 1px transparent;
-}
-
-.oo-ui-barToolGroup .oo-ui-tool-link {
-       display: block;
-       height: 1.5em;
-       padding: 0.25em;
-       cursor: pointer;
-}
-
-.oo-ui-barToolGroup
-       .oo-ui-tool-active:not(.oo-ui-widget-disabled) +
-       .oo-ui-tool-active:not(.oo-ui-widget-disabled)
-{
-       border-left-color: rgba(0,0,0,0.1);
-}
-
-.oo-ui-barToolGroup .oo-ui-tool:first-child {
-       border-top-left-radius: 0.25em;
-       border-bottom-left-radius: 0.25em;
-}
-
-.oo-ui-barToolGroup .oo-ui-tool:last-child {
-       margin-right: -1px;
-       border-top-right-radius: 0.25em;
-       border-bottom-right-radius: 0.25em;
-}
-
-.oo-ui-barToolGroup .oo-ui-tool:hover:not(.oo-ui-widget-disabled) {
-       border-color: rgba(0,0,0,0.2);
-}
-
-.oo-ui-barToolGroup .oo-ui-tool-active:not(.oo-ui-widget-disabled) {
-       border-color: rgba(0,0,0,0.2);
-}
-
-.oo-ui-barToolGroup .oo-ui-tool-link .oo-ui-iconedElement-icon {
-       display: block;
-       height: 1.5em;
-       width: 1.5em;
-       opacity: 0.8;
-}
-
-.oo-ui-barToolGroup .oo-ui-tool-link .oo-ui-tool-title {
-       display: none;
-}
-
-.oo-ui-barToolGroup .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-link {
-       cursor: default;
-}
-
-.oo-ui-barToolGroup .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-link .oo-ui-iconedElement-icon {
-       opacity: 0.2;
-}
-
-.oo-ui-barToolGroup .oo-ui-tool:not(.oo-ui-widget-disabled) .oo-ui-tool-link .oo-ui-iconedElement-icon {
-       opacity: 0.8;
-}
-
-.oo-ui-barToolGroup .oo-ui-tool:hover:not(.oo-ui-widget-disabled) .oo-ui-tool-link .oo-ui-iconedElement-icon {
-       opacity: 1;
-}
-
-.oo-ui-barToolGroup .oo-ui-tool-title {
-       display: none;
-}
-
-/* OO.ui.PopupToolGroup */
-
-.oo-ui-popupToolGroup {
-       position: relative;
-       height: 2em;
-       min-width: 2.5em;
-}
-
-.oo-ui-popupToolGroup.oo-ui-indicatedElement.oo-ui-iconedElement {
-       min-width: 3.5em;
-}
-
-.oo-ui-popupToolGroup-handle {
-       display: block;
-       cursor: pointer;
-}
-
-.oo-ui-popupToolGroup-handle .oo-ui-indicatedElement-indicator,
-.oo-ui-popupToolGroup-handle .oo-ui-iconedElement-icon {
-       position: absolute;
-       top: 0;
-       width: 2em;
-       height: 2em;
-       background-position: center center;
-       background-repeat: no-repeat;
-       opacity: 0.8;
-}
-
-.oo-ui-popupToolGroup-handle .oo-ui-indicatedElement-indicator {
-       right: 0;
-}
-
-.oo-ui-popupToolGroup-handle .oo-ui-iconedElement-icon {
-       left: 0.25em;
-}
-
-.oo-ui-popupToolGroup-handle .oo-ui-labeledElement-label {
-       line-height: 2.6em;
-       font-size: 0.8em;
-       margin: 0 1em;
-}
-
-.oo-ui-popupToolGroup.oo-ui-iconedElement .oo-ui-popupToolGroup-handle .oo-ui-labeledElement-label {
-       margin-left: 3.25em;
-}
-
-.oo-ui-popupToolGroup.oo-ui-indicatedElement .oo-ui-popupToolGroup-handle .oo-ui-labeledElement-label {
-       margin-right: 2.25em;
-}
-
-.oo-ui-popupToolGroup .oo-ui-toolGroup-tools {
-       display: none;
-       position: absolute;
-       top: 2em;
-       left: -1px;
-       z-index: 4;
-       border: solid 1px #ccc;
-       background-color: white;
-       box-shadow: 0 0.25em 1em rgba(0,0,0,0.25);
-}
-
-.oo-ui-popupToolGroup .oo-ui-toolGroup-tools .oo-ui-iconedElement-icon {
-       background-repeat: no-repeat;
-       background-position: center center;
-}
-
-.oo-ui-popupToolGroup-active:not(.oo-ui-widget-disabled) > .oo-ui-toolGroup-tools {
-       display: block;
-}
-
-.oo-ui-popupToolGroup-active:not(.oo-ui-widget-disabled) {
-       border-bottom-left-radius: 0;
-       border-bottom-right-radius: 0;
-}
-
-.oo-ui-popupToolGroup .oo-ui-tool-link .oo-ui-iconedElement-icon {
-       display: inline-block;
-       vertical-align: middle;
-       height: 2em;
-       width: 2em;
-       margin-right: 0.5em;
-}
-
-.oo-ui-popupToolGroup .oo-ui-tool-link .oo-ui-tool-title {
-       display: inline-block;
-       vertical-align: middle;
-       line-height: 2em;
-       font-size: 0.8em;
-}
-
-.oo-ui-popupToolGroup .oo-ui-tool-accel {
-       display: none;
-}
-
-/* OO.ui.ListToolGroup */
-
-.oo-ui-listToolGroup .oo-ui-toolGroup-tools {
-       padding: 0.25em;
-}
-
-.oo-ui-listToolGroup .oo-ui-tool {
-       display: inline-block;
-       width: 100%;
-       -webkit-box-sizing: border-box;
-       -moz-box-sizing: border-box;
-       box-sizing: border-box;
-       border: solid 1px transparent;
-       margin: -1px 0;
-}
-
-.oo-ui-listToolGroup .oo-ui-tool-link {
-       display: block;
-       cursor: pointer;
-       white-space: nowrap;
-       padding-right: 0.5em;
-}
-
-.oo-ui-listToolGroup.oo-ui-popupToolGroup-active {
-       border-color: rgba(0,0,0,0.2);
-}
-
-.oo-ui-listToolGroup
-       .oo-ui-tool-active:not(.oo-ui-widget-disabled) +
-       .oo-ui-tool-active:not(.oo-ui-widget-disabled)
-{
-       border-top-color: rgba(0,0,0,0.1);
-}
-
-.oo-ui-listToolGroup .oo-ui-tool:hover:not(.oo-ui-widget-disabled) {
-       border-color: rgba(0,0,0,0.2);
-}
-
-.oo-ui-listToolGroup .oo-ui-tool-active:not(.oo-ui-widget-disabled) {
-       border-color: rgba(0,0,0,0.2);
-}
-
-.oo-ui-listToolGroup .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-link {
-       cursor: default;
-}
-
-.oo-ui-listToolGroup .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-link .oo-ui-tool-title {
-       color: #ccc;
-}
-
-.oo-ui-listToolGroup .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-link .oo-ui-iconedElement-icon {
-       opacity: 0.2;
-}
-
-.oo-ui-listToolGroup .oo-ui-tool:not(.oo-ui-widget-disabled) .oo-ui-tool-link .oo-ui-iconedElement-icon {
-       opacity: 0.8;
-}
-
-.oo-ui-listToolGroup .oo-ui-tool:hover:not(.oo-ui-widget-disabled) .oo-ui-tool-link .oo-ui-iconedElement-icon {
-       opacity: 1;
-}
-
-/* OO.ui.MenuToolGroup */
-
-.oo-ui-menuToolGroup {
-       border-color: rgba(0,0,0,0.1);
-}
-
-.oo-ui-menuToolGroup:hover {
-       border-color: rgba(0,0,0,0.2);
-}
-
-.oo-ui-menuToolGroup.oo-ui-popupToolGroup-active {
-       border-color: rgba(0,0,0,0.25);
-}
-
-.oo-ui-menuToolGroup .oo-ui-popupToolGroup-handle {
-       min-width: 8em;
-}
-
-.oo-ui-menuToolGroup .oo-ui-tool {
-       display: block;
-}
-
-.oo-ui-menuToolGroup .oo-ui-tool-link {
-       display: block;
-       cursor: pointer;
-       white-space: nowrap;
-       padding: 0.25em 1em 0.25em 0.25em;
-}
-
-.oo-ui-menuToolGroup .oo-ui-tool-link .oo-ui-iconedElement-icon {
-       background-image: none;
-}
-
-.oo-ui-menuToolGroup .oo-ui-tool-active .oo-ui-tool-link .oo-ui-iconedElement-icon {
-       /* @embed */
-       background-image: url(images/icons/check.png);
-}
-
-.oo-ui-menuToolGroup .oo-ui-tool:hover {
-       background-color: #e1f3ff;
-}
-
-/* Common */
-
-.oo-ui-barToolGroup .oo-ui-tool-active:not(.oo-ui-widget-disabled),
-.oo-ui-listToolGroup .oo-ui-tool-active:not(.oo-ui-widget-disabled),
-.oo-ui-popupToolGroup-active:not(.oo-ui-widget-disabled) {
-       /* @embed */
-       background-image: url(images/fade-down.png);
-       background-position: left top;
-       background-repeat: repeat-x;
-       box-shadow: inset 0 0.07em 0.07em 0 rgba(0, 0, 0, 0.07);
-}
-/* OO.ui.ButtonWidget */
-
-.oo-ui-buttonWidget {
-       display: inline-block;
-       vertical-align: middle;
-}
-
-/* OO.ui.PopupButtonWidget */
-
-.oo-ui-popupButtonWidget {
-       position: relative;
-}
-
-.oo-ui-popupButtonWidget .oo-ui-popupWidget {
-       position: absolute;
-       left: 1em;
-       cursor: auto;
-}
-
-/* OO.ui.ButtonGroupWidget */
-
-.oo-ui-buttonGroupWidget {
-       display: inline-block;
-       border-radius: 0.3em;
-       box-shadow: 0 0.1em 0.25em rgba(0, 0, 0, 0.1);
-}
-
-.oo-ui-buttonGroupWidget .oo-ui-buttonedElement-framed .oo-ui-buttonedElement-button {
-       border-radius: 0;
-       margin-bottom: -1px;
-       margin-left: -1px;
-       box-shadow: none;
-}
-
-.oo-ui-buttonGroupWidget .oo-ui-buttonedElement-framed:first-child .oo-ui-buttonedElement-button {
-       border-bottom-left-radius: 0.3em;
-       border-top-left-radius: 0.3em;
-       margin-left: 0;
-}
-
-.oo-ui-buttonGroupWidget .oo-ui-buttonedElement-framed:last-child .oo-ui-buttonedElement-button {
-       border-bottom-right-radius: 0.3em;
-       border-top-right-radius: 0.3em;
-}
-
-/* OO.ui.SelectWidget */
-
-.oo-ui-selectWidget {
-       list-style: none;
-       margin: 0;
-       padding: 0;
-}
-
-/* OO.ui.OptionWidget */
-
-.oo-ui-optionWidget {
-       position: relative;
-       display: block;
-       border: none;
-       list-style: none;
-       margin: 0;
-       padding: 0.5em 2em 0.5em 3em;
-       cursor: pointer;
-}
-
-.oo-ui-optionWidget .oo-ui-labeledElement-label {
-       line-height: 1.5em;
-       white-space: nowrap;
-       text-overflow: ellipsis;
-       overflow: hidden;
-}
-
-.oo-ui-optionWidget-highlighted {
-       background-color: #e1f3ff;
-}
-
-.oo-ui-optionWidget-selected {
-       background-color: #a7dcff;
-}
-
-.oo-ui-optionWidget.oo-ui-widget-disabled {
-       cursor: default;
-}
-
-.oo-ui-optionWidget .oo-ui-iconedElement-icon,
-.oo-ui-optionWidget .oo-ui-indicatedElement-indicator {
-       position: absolute;
-       top: 50%;
-       width: 2em;
-       height: 2em;
-       margin-top: -1em;
-       background-repeat: no-repeat;
-       background-position: center center;
-}
-
-.oo-ui-optionWidget .oo-ui-iconedElement-icon {
-       left: 0.5em;
-}
-
-.oo-ui-optionWidget .oo-ui-indicatedElement-indicator {
-       right: 0.5em;
-}
-
-/* OO.ui.OutlineItemWidget */
-
-.oo-ui-outlineItemWidget {
-       position: relative;
-       padding: 0.75em 0.75em 0.75em 3.5em;
-       -webkit-user-select: none;
-       -moz-user-select: none;
-       -ms-user-select: none;
-       user-select: none;
-       cursor: pointer;
-       font-size: 1.1em;
-}
-
-.oo-ui-outlineItemWidget-level-1 {
-       padding-left: 5em;
-}
-
-.oo-ui-outlineItemWidget-level-2 {
-       padding-left: 6.5em;
-}
-
-.oo-ui-outlineItemWidget.oo-ui-optionWidget-selected {
-       background-color: #a7dcff;
-       text-shadow: 0 1px 1px rgba(255,255,255,0.5);
-}
-
-.oo-ui-outlineItemWidget-level-0 .oo-ui-iconedElement-icon {
-       left: 1em;
-}
-
-.oo-ui-outlineItemWidget-level-1 .oo-ui-iconedElement-icon {
-       left: 2.5em;
-}
-
-.oo-ui-outlineItemWidget-level-2 .oo-ui-iconedElement-icon {
-       left: 4em;
-}
-
-/* OO.ui.OutlineControlsWidget */
-
-.oo-ui-outlineControlsWidget {
-       height: 3em;
-       background-color: #fff;
-}
-
-.oo-ui-outlineControlsWidget-adders,
-.oo-ui-outlineControlsWidget-movers {
-       float: left;
-       -webkit-box-sizing: border-box;
-       -moz-box-sizing: border-box;
-       box-sizing: border-box;
-       height: 3em;
-       padding: 0.5em;
-}
-
-.oo-ui-outlineControlsWidget-adders {
-       float: left;
-}
-.oo-ui-outlineControlsWidget-movers {
-       float: right;
-}
-
-.oo-ui-outlineControlsWidget-adders .oo-ui-buttonWidget {
-       float: left;
-}
-
-.oo-ui-outlineControlsWidget-movers .oo-ui-buttonWidget {
-       float: right;
-}
-
-.oo-ui-outlineControlsWidget-adders .oo-ui-buttonWidget:first-child,
-.oo-ui-outlineControlsWidget-adders .oo-ui-buttonWidget:first-child:hover {
-       opacity: 0.25;
-       cursor: default;
-}
-
-/* OO.ui.InputLabelWidget */
-
-.oo-ui-inputLabelWidget {
-       padding: 0.5em 0;
-}
-
-/* OO.ui.TextInputWidget */
-
-.oo-ui-textInputWidget {
-       -webkit-box-sizing: border-box;
-       -moz-box-sizing: border-box;
-       box-sizing: border-box;
-       width: 20em;
-       position: relative;
-}
-
-.oo-ui-textInputWidget input,
-.oo-ui-textInputWidget input:focus[readonly],
-.oo-ui-widget-disabled.oo-ui-textInputWidget input:focus,
-.oo-ui-textInputWidget textarea,
-.oo-ui-textInputWidget textarea:focus[readonly],
-.oo-ui-widget-disabled.oo-ui-textInputWidget textarea:focus {
-       display: inline-block;
-       font-size: 1em;
-       font-family: sans-serif;
-       background-color: #f7f7f7;
-       border: solid 1px #ccc;
-       box-shadow: 0 0 0 white, inset 0 0.1em 0.2em #ddd;
-       padding: 0.5em;
-       border-radius: 0.25em;
-       -webkit-box-sizing: border-box;
-       -moz-box-sizing: border-box;
-       box-sizing: border-box;
-       width: 100%;
-       resize: none;
-
-       /* Animation */
-       -webkit-transition: border-color 200ms, box-shadow 200ms, background-color 200ms;
-       -moz-transition: border-color 200ms, box-shadow 200ms, background-color 200ms;
-       -o-transition: border-color 200ms, box-shadow 200ms, background-color 200ms;
-       transition: border-color 200ms, box-shadow 200ms, background-color 200ms;
-}
-
-.oo-ui-textInputWidget-pending input,
-.oo-ui-textInputWidget-pending textarea {
-       background-color: transparent;
-}
-
-.oo-ui-textInputWidget input:focus,
-.oo-ui-textInputWidget textarea:focus {
-       outline: none;
-       border-color: #a7dcff;
-       box-shadow: 0 0 0.3em #a7dcff, 0 0 0 white;
-       background-color: #fff;
-}
-
-.oo-ui-textInputWidget input[readonly],
-.oo-ui-textInputWidget textarea[readonly] {
-       color: #777;
-       text-shadow: 0 1px 1px #fff;
-}
-
-.oo-ui-widget-disabled.oo-ui-textInputWidget input,
-.oo-ui-widget-disabled.oo-ui-textInputWidget input:focus,
-.oo-ui-widget-disabled.oo-ui-textInputWidget textarea,
-.oo-ui-widget-disabled.oo-ui-textInputWidget textarea:focus {
-       color: #ccc;
-       text-shadow: 0 1px 1px #fff;
-}
-
-.oo-ui-textInputWidget-decorated input,
-.oo-ui-textInputWidget-decorated textarea {
-       padding-left: 2em;
-}
-
-.oo-ui-textInputWidget-icon {
-       position: absolute;
-       top: 0;
-       left: 0;
-       width: 2em;
-       height: 100%;
-       background-position: right center;
-       background-repeat: no-repeat;
-}
-
-/* OO.ui.CheckboxWidget */
-.oo-ui-checkboxWidget .oo-ui-labeledElement-label {
-       display: inline-block;
-       vertical-align: middle;
-       padding-left: 0.5em;
-}
-
-.oo-ui-checkboxWidget input {
-       vertical-align: middle;
-}
-
-.oo-ui-checkboxWidget.oo-ui-widget-disabled .oo-ui-labeledElement-label {
-       opacity: 0.5;
-}
-
-/* OO.ui.MenuWidget */
-
-.oo-ui-menuWidget {
-       position: absolute;
-       background: #fff;
-       margin-top: -1px;
-       border: solid 1px #ccc;
-       border-radius: 0 0 0.25em 0.25em;
-       box-shadow: 0 0.15em 1em 0 rgba(0, 0, 0, 0.2);
-}
-
-.oo-ui-menuWidget input {
-       position: absolute;
-       width: 0;
-       height: 0;
-       overflow: hidden;
-       opacity: 0;
-}
-
-/* OO.ui.MenuItemWidget */
-
-.oo-ui-menuItemWidget {
-       position: relative;
-}
-
-.oo-ui-menuItemWidget .oo-ui-iconedElement-icon {
-       display: none;
-}
-
-.oo-ui-menuItemWidget.oo-ui-optionWidget-selected .oo-ui-iconedElement-icon {
-       display: block;
-}
-
-.oo-ui-menuItemWidget.oo-ui-optionWidget-selected {
-       background-color: transparent;
-}
-
-.oo-ui-menuItemWidget.oo-ui-optionWidget-highlighted {
-       background-color: #e1f3ff;
-}
-
-/* OO.ui.MenuSectionItemWidget */
-
-.oo-ui-menuSectionItemWidget {
-       padding: 0.33em 0.75em;
-       color: #888;
-       cursor: default;
-}
-
-/* OO.ui.ButtonSelectWidget */
-
-.oo-ui-buttonSelectWidget {
-       display: inline-block;
-       border-radius: 0.3em;
-       box-shadow: 0 0.1em 0.25em rgba(0, 0, 0, 0.1);
-}
-
-.oo-ui-buttonSelectWidget .oo-ui-buttonOptionWidget .oo-ui-buttonedElement-button {
-       border-radius: 0;
-       margin-left: -1px;
-       box-shadow: none;
-}
-
-.oo-ui-buttonSelectWidget .oo-ui-buttonOptionWidget:first-child .oo-ui-buttonedElement-button {
-       border-bottom-left-radius: 0.3em;
-       border-top-left-radius: 0.3em;
-       margin-left: 0;
-}
-
-.oo-ui-buttonSelectWidget .oo-ui-buttonOptionWidget:last-child .oo-ui-buttonedElement-button {
-       border-bottom-right-radius: 0.3em;
-       border-top-right-radius: 0.3em;
-}
-
-/* OO.ui.ButtonOptionWidget */
-
-.oo-ui-buttonOptionWidget {
-       display: inline-block;
-       padding: 0;
-       background-color: transparent;
-}
-
-.oo-ui-buttonOptionWidget .oo-ui-buttonedElement-button {
-       position: relative;
-       height: 1.9em;
-}
-
-.oo-ui-buttonOptionWidget.oo-ui-iconedElement .oo-ui-iconedElement-icon,
-.oo-ui-buttonOptionWidget.oo-ui-indicatedElement .oo-ui-indicatedElement-indicator {
-       position: static;
-       display: inline-block;
-       vertical-align: middle;
-       height: 1.9em;
-       margin-top: 0;
-}
-
-/* OO.ui.PopupWidget */
-
-.oo-ui-popupWidget-popup {
-       position: absolute;
-       overflow: hidden;
-       border: solid 1px #ccc;
-       border-radius: 0.25em;
-       background-color: #fff;
-       box-shadow: 0 0.15em 0.5em 0 rgba(0, 0, 0, 0.2);
-}
-
-.oo-ui-popupWidget-tail {
-       display: none;
-}
-
-.oo-ui-popupWidget-tailed .oo-ui-popupWidget-popup {
-       margin-top: 7px;
-}
-
-.oo-ui-popupWidget-tailed .oo-ui-popupWidget-tail {
-       display: block;
-       position: absolute;
-       /* @embed */
-       background-image: url(images/tail.svg);
-       background-repeat: no-repeat;
-       width: 15px;
-       height: 8px;
-       margin-left: -7px;
-}
-
-.oo-ui-popupWidget-transitioning .oo-ui-popupWidget-popup {
-       -webkit-transition: width 100ms, height 100ms, left 100ms;
-       -moz-transition: width 100ms, height 100ms, left 100ms;
-       -o-transition: width 100ms, height 100ms, left 100ms;
-       transition: width 100ms, height 100ms, left 100ms;
-       -webkit-transition-timing-function: ease-in-out;
-       -moz-transition-timing-function: ease-in-out;
-       -o-transition-timing-function: ease-in-out;
-       transition-timing-function: ease-in-out;
-}
-
-.oo-ui-popupWidget-head {
-       height: 2.5em;
-       -webkit-touch-callout: none;
-       -webkit-user-select: none;
-       -moz-user-select: none;
-       -ms-user-select: none;
-       user-select: none;
-}
-
-.oo-ui-popupWidget-head .oo-ui-buttonWidget {
-       float: right;
-       margin: 0.25em;
-}
-
-.oo-ui-popupWidget-head .oo-ui-labeledElement-label {
-       float: left;
-       margin: 0.75em 1em;
-       cursor: default;
-}
-
-.oo-ui-popupWidget-body {
-       box-shadow: 0 0 0.66em rgba(0,0,0,0.25);
-}
-
-/* OO.ui.SearchWidget */
-
-.oo-ui-searchWidget-query {
-       position: absolute;
-       top: 0;
-       left: 0;
-       right: 0;
-       height: 4em;
-       padding: 0 1em;
-       box-shadow: 0 0 0.5em rgba(0,0,0,0.2);
-}
-
-.oo-ui-searchWidget-query .oo-ui-textInputWidget {
-       width: 100%;
-       margin: 0.75em 0;
-}
-
-.oo-ui-searchWidget-results {
-       position: absolute;
-       top: 4em;
-       bottom: 0;
-       left: 0;
-       right: 0;
-       padding: 1em;
-       overflow-x: hidden;
-       overflow-y: auto;
-       line-height: 0;
-}
-
-/* OO.ui.ToggleSwitchWidget */
-
-.oo-ui-toggleSwitchWidget {
-       position: relative;
-       display: inline-block;
-       vertical-align: middle;
-       height: 2em;
-       width: 3em;
-       border-radius: 1em;
-       overflow: hidden;
-       box-shadow: 0 0 0 white, inset 0 0.1em 0.2em #ddd;
-       border: solid 1px #ccc;
-       cursor: pointer;
-       -webkit-box-sizing: border-box;
-       -moz-box-sizing: border-box;
-       box-sizing: border-box;
-       -webkit-transform: translateZ(0px);
-       -moz-transform: translateZ(0px);
-       -ms-transform: translateZ(0px);
-       -o-transform: translateZ(0px);
-       transform: translateZ(0px);
-
-       /* Gray */
-       background-color: #dddddd;
-       filter: progid:DXImageTransform.Microsoft.gradient(
-               GradientType=0,startColorstr=#dddddd, endColorstr=#ffffff
-       );
-       background-image: -webkit-gradient(
-               linear, right top, right bottom, color-stop(0%,#dddddd), color-stop(100%,#ffffff)
-       );
-       background-image: -webkit-linear-gradient(top, #dddddd 0%, #ffffff 100%);
-       background-image: -moz-linear-gradient(top, #dddddd 0%, #ffffff 100%);
-       background-image: -ms-linear-gradient(top, #dddddd 0%, #ffffff 100%);
-       background-image: -o-linear-gradient(top, #dddddd 0%, #ffffff 100%);
-       background-image: linear-gradient(top, #dddddd 0%, #ffffff 100%);
-}
-
-.oo-ui-toggleSwitchWidget.oo-ui-widget-disabled {
-       opacity: 0.5;
-}
-
-.oo-ui-toggleSwitchWidget-grip {
-       -webkit-transition: left 200ms ease-in-out, margin-left 200ms ease-in-out;
-       -moz-transition: left 200ms ease-in-out, margin-left 200ms ease-in-out;
-       -o-transition: left 200ms ease-in-out, margin-left 200ms ease-in-out;
-       transition: left 200ms ease-in-out, margin-left 200ms ease-in-out;
-}
-
-.oo-ui-toggleSwitchWidget-grip {
-       position: absolute;
-       display: block;
-       top: 0.25em;
-       left: 0.25em;
-       width: 1.5em;
-       height: 1.5em;
-       border-radius: 1em;
-       box-shadow: 0 0.1em 0.25em rgba(0, 0, 0, 0.1);
-       -webkit-box-sizing: border-box;
-       -moz-box-sizing: border-box;
-       box-sizing: border-box;
-
-       /* Gray */
-       border: 1px #c9c9c9 solid;
-       background-color: #ffffff;
-       filter: progid:DXImageTransform.Microsoft.gradient(
-               GradientType=0,startColorstr=#ffffff, endColorstr=#dddddd
-       );
-       background-image: -webkit-gradient(
-               linear, right top, right bottom, color-stop(0%,#ffffff), color-stop(100%,#dddddd)
-       );
-       background-image: -webkit-linear-gradient(top, #ffffff 0%, #dddddd 100%);
-       background-image: -moz-linear-gradient(top, #ffffff 0%, #dddddd 100%);
-       background-image: -ms-linear-gradient(top, #ffffff 0%, #dddddd 100%);
-       background-image: -o-linear-gradient(top, #ffffff 0%, #dddddd 100%);
-       background-image: linear-gradient(top, #ffffff 0%, #dddddd 100%);
-}
-
-.oo-ui-toggleSwitchWidget:not(.oo-ui-widget-disabled):hover,
-.oo-ui-toggleSwitchWidget:not(.oo-ui-widget-disabled):hover .oo-ui-toggleSwitchWidget-grip {
-       border-color: #aaa;
-}
-
-.oo-ui-toggleWidget-on .oo-ui-toggleSwitchWidget-grip {
-       left: 1.25em;
-       margin-left: -2px;
-}
-
-.oo-ui-toggleWidget-off .oo-ui-toggleSwitchWidget-grip {
-       left: 0.25em;
-       margin-left: 0;
-}
-
-.oo-ui-toggleSwitchWidget .oo-ui-toggleSwitchWidget-on {
-       position: absolute;
-       top: 0;
-       bottom: 0;
-       right: 0;
-       left: 0;
-       border-radius: 1em;
-       box-shadow: inset 0 1px 4px 0 rgba(0, 0, 0, 0.07);
-       cursor: pointer;
-       -webkit-touch-callout: none;
-       -webkit-user-select: none;
-       -moz-user-select: none;
-       -ms-user-select: none;
-       user-select: none;
-
-       -webkit-transition: opacity 200ms ease-in-out;
-       -moz-transition: opacity 200ms ease-in-out;
-       -o-transition: opacity 200ms ease-in-out;
-       transition: opacity 200ms ease-in-out;
-
-       /* Blue */
-       background-color: #eaf4fa;
-       filter: progid:DXImageTransform.Microsoft.gradient(
-               GradientType=0,startColorstr=#b0d9ee, endColorstr=#eaf4fa
-       );
-       background-image: -webkit-gradient(
-               linear, right top, right bottom, color-stop(0%,#b0d9ee), color-stop(100%,#eaf4fa)
-       );
-       background-image: -webkit-linear-gradient(top, #b0d9ee 0%, #eaf4fa 100%);
-       background-image: -moz-linear-gradient(top, #b0d9ee 0%, #eaf4fa 100%);
-       background-image: -ms-linear-gradient(top, #b0d9ee 0%, #eaf4fa 100%);
-       background-image: -o-linear-gradient(top, #b0d9ee 0%, #eaf4fa 100%);
-       background-image: linear-gradient(top, #b0d9ee 0%, #eaf4fa 100%);
-}
-
-.oo-ui-toggleWidget-on .oo-ui-toggleSwitchWidget-on {
-       opacity: 1;
-}
-
-.oo-ui-toggleWidget-off .oo-ui-toggleSwitchWidget-on {
-       opacity: 0;
-}
-.oo-ui-window-head {
-       -webkit-touch-callout: none;
-       -webkit-user-select: none;
-       -moz-user-select: none;
-       -ms-user-select: none;
-       user-select: none;
-}
-
-.oo-ui-window-body {
-       padding: 0 0.75em;
-}
-
-.oo-ui-window-icon {
-       float: left;
-       width: 2em;
-       height: 2em;
-       line-height: 2em;
-       margin-right: 0.5em;
-       background-position: right center;
-       background-repeat: no-repeat;
-}
-
-.oo-ui-window-title {
-       float: left;
-       line-height: 2em;
-       color: #333;
-       white-space: nowrap;
-       cursor: default;
-}
-
-.oo-ui-window-overlay {
-       font-family: sans-serif;
-       line-height: 1.5em;
-       font-size: 1em;
-       position: absolute;
-       top: 0;
-       left: 0;
-}
-/* Icons */
-
-.oo-ui-icon-add-item {
-       /* @embed */
-       background-image: url(images/icons/add-item.png);
-}
-
-.oo-ui-icon-advanced {
-       /* @embed */
-       background-image: url(images/icons/advanced.png);
-}
-
-.oo-ui-icon-alert {
-       /* @embed */
-       background-image: url(images/icons/alert.png);
-}
-
-.oo-ui-icon-check {
-       /* @embed */
-       background-image: url(images/icons/check.png);
-}
-
-.oo-ui-icon-clear {
-       /* @embed */
-       background-image: url(images/icons/clear.png);
-}
-
-.oo-ui-icon-close {
-       /* @embed */
-       background-image: url(images/icons/close.png);
-}
-
-.oo-ui-icon-code {
-       /* @embed */
-       background-image: url(images/icons/code.png);
-}
-
-.oo-ui-icon-collapse {
-       /* @embed */
-       background-image: url(images/icons/collapse.png);
-}
-
-.oo-ui-icon-comment {
-       /* @embed */
-       background-image: url(images/icons/comment.png);
-}
-
-.oo-ui-icon-expand {
-       /* @embed */
-       background-image: url(images/icons/expand.png);
-}
-
-.oo-ui-icon-help {
-       /* @embed */
-       background-image: url(images/icons/help.png);
-}
-
-.oo-ui-icon-link {
-       /* @embed */
-       background-image: url(images/icons/link.png);
-}
-
-.oo-ui-icon-menu {
-       /* @embed */
-       background-image: url(images/icons/menu.png);
-}
-
-.oo-ui-icon-next {
-       /* @embed */
-       background-image: url(images/icons/move-ltr.png);
-}
-
-.oo-ui-icon-picture {
-       /* @embed */
-       background-image: url(images/icons/picture.png);
-}
-
-.oo-ui-icon-previous {
-       /* @embed */
-       background-image: url(images/icons/move-rtl.png);
-}
-
-.oo-ui-icon-redo {
-       /* @embed */
-       background-image: url(images/icons/arched-arrow-ltr.png);
-}
-
-.oo-ui-icon-remove {
-       /* @embed */
-       background-image: url(images/icons/remove.png);
-}
-
-.oo-ui-icon-search {
-       /* @embed */
-       background-image: url(images/icons/search.png);
-}
-
-.oo-ui-icon-settings {
-       /* @embed */
-       background-image: url(images/icons/settings.png);
-}
-
-.oo-ui-icon-tag {
-       /* @embed */
-       background-image: url(images/icons/tag.png);
-}
-
-.oo-ui-icon-undo {
-       /* @embed */
-       background-image: url(images/icons/arched-arrow-rtl.png);
-}
-
-.oo-ui-icon-window {
-       /* @embed */
-       background-image: url(images/icons/window.png);
-}
-
-/* Indicators */
-
-.oo-ui-indicator-down {
-       /* @embed */
-       background-image: url(images/indicators/down.png);
-}
-
-.oo-ui-indicator-required {
-       /* @embed */
-       background-image: url(images/indicators/required.png);
-}
-
-.oo-ui-indicator-up {
-       /* @embed */
-       background-image: url(images/indicators/up.png);
-}
-/* Icons */
-
-.oo-ui-icon-add-item {
-       /* @embed */
-       background-image: url(images/icons/add-item.svg);
-}
-
-.oo-ui-icon-advanced {
-       /* @embed */
-       background-image: url(images/icons/advanced.svg);
-}
-
-.oo-ui-icon-alert {
-       /* @embed */
-       background-image: url(images/icons/alert.svg);
-}
-
-.oo-ui-icon-check {
-       /* @embed */
-       background-image: url(images/icons/check.svg);
-}
-
-.oo-ui-icon-clear {
-       /* @embed */
-       background-image: url(images/icons/clear.svg);
-}
-
-.oo-ui-icon-close {
-       /* @embed */
-       background-image: url(images/icons/close.svg);
-}
-
-.oo-ui-icon-code {
-       /* @embed */
-       background-image: url(images/icons/code.svg);
-}
-
-.oo-ui-icon-collapse {
-       /* @embed */
-       background-image: url(images/icons/collapse.svg);
-}
-
-.oo-ui-icon-comment {
-       /* @embed */
-       background-image: url(images/icons/comment.svg);
-}
-
-.oo-ui-icon-expand {
-       /* @embed */
-       background-image: url(images/icons/expand.svg);
-}
-
-.oo-ui-icon-help {
-       /* @embed */
-       background-image: url(images/icons/help.svg);
-}
-
-.oo-ui-icon-link {
-       /* @embed */
-       background-image: url(images/icons/link.svg);
-}
-
-.oo-ui-icon-menu {
-       /* @embed */
-       background-image: url(images/icons/menu.svg);
-}
-
-.oo-ui-icon-next {
-       /* @embed */
-       background-image: url(images/icons/move-ltr.svg);
-}
-
-.oo-ui-icon-picture {
-       /* @embed */
-       background-image: url(images/icons/picture.svg);
-}
-
-.oo-ui-icon-previous {
-       /* @embed */
-       background-image: url(images/icons/move-rtl.svg);
-}
-
-.oo-ui-icon-redo {
-       /* @embed */
-       background-image: url(images/icons/arched-arrow-ltr.svg);
-}
-
-.oo-ui-icon-remove {
-       /* @embed */
-       background-image: url(images/icons/remove.svg);
-}
-
-.oo-ui-icon-search {
-       /* @embed */
-       background-image: url(images/icons/search.svg);
-}
-
-.oo-ui-icon-settings {
-       /* @embed */
-       background-image: url(images/icons/settings.svg);
-}
-
-.oo-ui-icon-tag {
-       /* @embed */
-       background-image: url(images/icons/tag.svg);
-}
-
-.oo-ui-icon-undo {
-       /* @embed */
-       background-image: url(images/icons/arched-arrow-rtl.svg);
-}
-
-.oo-ui-icon-window {
-       /* @embed */
-       background-image: url(images/icons/window.svg);
-}
-
-/* Indicators */
-
-.oo-ui-indicator-down {
-       /* @embed */
-       background-image: url(images/indicators/down.svg);
-}
-
-.oo-ui-indicator-required {
-       /* @embed */
-       background-image: url(images/indicators/required.svg);
-}
-
-.oo-ui-indicator-up {
-       /* @embed */
-       background-image: url(images/indicators/up.svg);
-}
index 596dff5..7e24ae7 100644 (file)
@@ -120,8 +120,6 @@ div.vectorMenu {
        direction: ltr;
        /* @noflip */
        float: left;
-       /* SVG support using a transparent gradient to guarantee cross-browser
-        * compatibility (browsers able to understand gradient syntax support also SVG) */
        .background-image-svg('images/arrow-down-icon.svg', 'images/arrow-down-icon.png');
        /* @noflip */
        background-position: 100% 60%;
@@ -135,8 +133,6 @@ div.vectorMenu.menuForceShow {
 }
 
 div.vectorMenuFocus {
-       /* SVG support using a transparent gradient to guarantee cross-browser
-        * compatibility (browsers able to understand gradient syntax support also SVG) */
        .background-image-svg('images/arrow-down-focus-icon.svg', 'images/arrow-down-focus-icon.png');
        background-position: 100% 60%;
 }
index 542ffe7..2af6389 100644 (file)
@@ -36,8 +36,8 @@
 @menu-personal-font-size: 0.75em;
 
 // Collapsible nav
-@collapsible-nav-heading-color: #4D4D4D;
-@collapsible-nav-heading-collapsed-color: #0645AD;
+@collapsible-nav-heading-color: #4d4d4d;
+@collapsible-nav-heading-collapsed-color: #0645ad;
 
 @collapsible-nav-heading-padding: 4px 0 3px 1.5em;
 @collapsible-nav-body-margin: 0 0 0 1.25em;
index 6e13e13..292c576 100644 (file)
@@ -17,6 +17,7 @@
                                // The values for gender are not significant,
                                // what matters is which of the values is choosen by the parser
                                'gender-msg': '$1: {{GENDER:$2|blue|pink|green}}',
+                               'gender-msg-currentuser': '{{GENDER:|blue|pink|green}}',
 
                                'plural-msg': 'Found $1 {{PLURAL:$1|item|items}}',
 
                assert.equal( formatParse( 'plural-msg', 2 ), 'Found 2 items', 'Plural test for english' );
        } );
 
-       QUnit.test( 'Gender', 11, function ( assert ) {
+       QUnit.test( 'Gender', 15, function ( assert ) {
+               var originalGender = mw.user.options.get( 'gender' );
+
                // TODO: These tests should be for mw.msg once mw.msg integrated with mw.jqueryMsg
                // TODO: English may not be the best language for these tests. Use a language like Arabic or Russian
-               var user = mw.user;
-
-               user.options.set( 'gender', 'male' );
+               mw.user.options.set( 'gender', 'male' );
                assert.equal(
                        formatParse( 'gender-msg', 'Bob', 'male' ),
                        'Bob: blue',
                        'Masculine from string "male"'
                );
                assert.equal(
-                       formatParse( 'gender-msg', 'Bob', user ),
+                       formatParse( 'gender-msg', 'Bob', mw.user ),
                        'Bob: blue',
                        'Masculine from mw.user object'
                );
-
-               user.options.set( 'gender', 'unknown' );
                assert.equal(
-                       formatParse( 'gender-msg', 'Foo', user ),
-                       'Foo: green',
-                       'Neutral from mw.user object' );
+                       formatParse( 'gender-msg-currentuser' ),
+                       'blue',
+                       'Masculine for current user'
+               );
+
+               mw.user.options.set( 'gender', 'female' );
                assert.equal(
                        formatParse( 'gender-msg', 'Alice', 'female' ),
                        'Alice: pink',
                        'Feminine from string "female"' );
+               assert.equal(
+                       formatParse( 'gender-msg', 'Alice', mw.user ),
+                       'Alice: pink',
+                       'Feminine from mw.user object'
+               );
+               assert.equal(
+                       formatParse( 'gender-msg-currentuser' ),
+                       'pink',
+                       'Feminine for current user'
+               );
+
+               mw.user.options.set( 'gender', 'unknown' );
+               assert.equal(
+                       formatParse( 'gender-msg', 'Foo', mw.user ),
+                       'Foo: green',
+                       'Neutral from mw.user object' );
                assert.equal(
                        formatParse( 'gender-msg', 'User' ),
                        'User: green',
                        'User: green',
                        'Neutral from string "unknown"'
                );
+               assert.equal(
+                       formatParse( 'gender-msg-currentuser' ),
+                       'green',
+                       'Neutral for current user'
+               );
 
                mw.messages.set( 'gender-msg-one-form', '{{GENDER:$1|User}}: $2 {{PLURAL:$2|edit|edits}}' );
 
                        ' test',
                        'Invalid syntax should result in {{gender}} simply being stripped away'
                );
+
+               mw.user.options.set( 'gender', originalGender );
        } );
 
        QUnit.test( 'Grammar', 2, function ( assert ) {